blob: 3f695fe073247b9ef39db16b153c7d4041a38e77 [file] [log] [blame]
Brian Carlstrom3e6251d2011-04-11 09:05:06 -07001/*
2 * Copyright (C) 2011 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.keychain;
18
Chad Brubaker2099a7d2016-05-02 13:13:23 -070019import android.app.BroadcastOptions;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070020import android.app.IntentService;
21import android.content.ContentValues;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070022import android.content.Context;
23import android.content.Intent;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070024import android.content.pm.PackageManager;
Robin Lee7e9d0452017-02-20 20:57:41 +000025import android.content.pm.StringParceledListSlice;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070026import android.database.Cursor;
27import android.database.DatabaseUtils;
28import android.database.sqlite.SQLiteDatabase;
29import android.database.sqlite.SQLiteOpenHelper;
Kenny Root6f1f03b2012-03-08 10:30:39 -080030import android.os.Binder;
Chad Brubaker2099a7d2016-05-02 13:13:23 -070031import android.os.Build;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070032import android.os.IBinder;
Kenny Root6f1f03b2012-03-08 10:30:39 -080033import android.os.Process;
Robin Lee93772c32014-09-02 14:53:50 +010034import android.os.UserHandle;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070035import android.security.Credentials;
36import android.security.IKeyChainService;
Selim Gurun39e36e52012-02-14 10:50:42 -080037import android.security.KeyChain;
Eran Messeri50ebe3f2017-12-11 16:58:33 +000038import android.security.keymaster.KeymasterArguments;
39import android.security.keymaster.KeymasterCertificateChain;
40import android.security.keymaster.KeymasterDefs;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070041import android.security.KeyStore;
Eran Messeri6d469272017-11-15 05:55:28 +000042import android.security.keystore.KeyGenParameterSpec;
43import android.security.keystore.ParcelableKeyGenParameterSpec;
44import android.text.TextUtils;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070045import android.util.Log;
Eran Messeri5844b632017-11-03 10:28:34 +000046import com.android.keychain.internal.GrantsDatabase;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070047import java.io.ByteArrayInputStream;
Brian Carlstroma58db542011-05-11 23:02:20 -070048import java.io.IOException;
Eran Messeri6d469272017-11-15 05:55:28 +000049import java.security.InvalidAlgorithmParameterException;
50import java.security.KeyPair;
51import java.security.KeyPairGenerator;
52import java.security.NoSuchAlgorithmException;
53import java.security.NoSuchProviderException;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070054import java.security.cert.CertificateException;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010055import java.security.cert.CertificateEncodingException;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070056import java.security.cert.CertificateFactory;
57import java.security.cert.X509Certificate;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010058import java.util.Set;
59import java.util.List;
60import java.util.ArrayList;
61import java.util.Collections;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070062
Kenny Root3048b6c2013-04-23 22:38:11 -070063import com.android.org.conscrypt.TrustedCertificateStore;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070064
Fred Quintanafb2e18e2011-07-13 14:54:05 -070065public class KeyChainService extends IntentService {
Selim Gurun39e36e52012-02-14 10:50:42 -080066
Fred Quintanafb2e18e2011-07-13 14:54:05 -070067 private static final String TAG = "KeyChain";
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070068
Fred Quintanafb2e18e2011-07-13 14:54:05 -070069 /** created in onCreate(), closed in onDestroy() */
Eran Messeri5844b632017-11-03 10:28:34 +000070 public GrantsDatabase mGrantsDb;
Robin Leeba755b12016-02-24 15:27:43 +000071
Fred Quintanafb2e18e2011-07-13 14:54:05 -070072 public KeyChainService() {
73 super(KeyChainService.class.getSimpleName());
74 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070075
76 @Override public void onCreate() {
77 super.onCreate();
Eran Messeri5844b632017-11-03 10:28:34 +000078 mGrantsDb = new GrantsDatabase(this);
Fred Quintanafb2e18e2011-07-13 14:54:05 -070079 }
80
81 @Override
82 public void onDestroy() {
83 super.onDestroy();
Eran Messeri5844b632017-11-03 10:28:34 +000084 mGrantsDb.destroy();
85 mGrantsDb = null;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070086 }
87
88 private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070089 private final KeyStore mKeyStore = KeyStore.getInstance();
Brian Carlstroma58db542011-05-11 23:02:20 -070090 private final TrustedCertificateStore mTrustedCertificateStore
91 = new TrustedCertificateStore();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070092
Kenny Root6f1f03b2012-03-08 10:30:39 -080093 @Override
94 public String requestPrivateKey(String alias) {
95 checkArgs(alias);
96
97 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias;
98 final int uid = Binder.getCallingUid();
Janis Danisevskisc394aea2017-06-07 10:20:45 -070099 return mKeyStore.grant(keystoreAlias, uid);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700100 }
101
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700102 @Override public byte[] getCertificate(String alias) {
Kenny Root6f1f03b2012-03-08 10:30:39 -0800103 checkArgs(alias);
104 return mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700105 }
106
Rubin Xu8714f062016-03-23 12:37:10 +0000107 @Override public byte[] getCaCertificates(String alias) {
108 checkArgs(alias);
109 return mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
110 }
111
Eran Messeri1223b5f2017-11-08 18:47:40 +0000112 @Override public boolean isUserSelectable(String alias) {
113 validateAlias(alias);
114 return mGrantsDb.isUserSelectable(alias);
115 }
116
117 @Override public void setUserSelectable(String alias, boolean isUserSelectable) {
118 validateAlias(alias);
119 checkSystemCaller();
120 mGrantsDb.setIsUserSelectable(alias, isUserSelectable);
121 }
122
Eran Messeri6d469272017-11-15 05:55:28 +0000123 @Override public boolean generateKeyPair(
124 String algorithm, ParcelableKeyGenParameterSpec parcelableSpec) {
125 checkSystemCaller();
126 final KeyGenParameterSpec spec = parcelableSpec.getSpec();
127 final String alias = spec.getKeystoreAlias();
128 // Validate the alias here to avoid relying on KeyGenParameterSpec c'tor preventing
129 // the creation of a KeyGenParameterSpec instance with a non-empty alias.
130 if (TextUtils.isEmpty(alias) || spec.getUid() != KeyStore.UID_SELF) {
131 Log.e(TAG, "Cannot generate key pair with empty alias or specified uid.");
132 return false;
133 }
134
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000135 if (spec.getAttestationChallenge() != null) {
136 Log.e(TAG, "Key generation request should not include an Attestation challenge.");
137 return false;
138 }
139
Eran Messeri6d469272017-11-15 05:55:28 +0000140 try {
141 KeyPairGenerator generator = KeyPairGenerator.getInstance(
142 algorithm, "AndroidKeyStore");
143 // Do not prepend USER_PRIVATE_KEY to the alias because
144 // AndroidKeyStoreKeyPairGeneratorSpi will helpfully prepend that in
145 // generateKeyPair.
146 generator.initialize(spec);
147 KeyPair kp = generator.generateKeyPair();
148 if (kp == null) {
149 Log.e(TAG, "Key generation failed.");
150 return false;
151 }
152 return true;
153 } catch (NoSuchAlgorithmException e) {
154 Log.e(TAG, "Invalid algorithm requested", e);
155 } catch (InvalidAlgorithmParameterException e) {
156 Log.e(TAG, "Invalid algorithm params", e);
157 } catch (NoSuchProviderException e) {
158 Log.e(TAG, "Could not find Keystore.", e);
159 }
160
161 return false;
162 }
163
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000164 @Override public boolean attestKey(
165 String alias, byte[] attestationChallenge,
166 KeymasterCertificateChain attestationChain) {
167 checkSystemCaller();
168 validateAlias(alias);
169
170 if (attestationChallenge == null) {
171 Log.e(TAG, String.format("Missing attestation challenge for alias %s", alias));
172 return false;
173 }
174
175 KeymasterArguments attestArgs = new KeymasterArguments();
176 attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, attestationChallenge);
177 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias;
178 final int errorCode = mKeyStore.attestKey(keystoreAlias, attestArgs, attestationChain);
179 return errorCode == KeyStore.NO_ERROR;
180 }
181
Eran Messeri4b18d652017-12-11 12:32:25 +0000182 @Override public boolean setKeyPairCertificate(String alias, byte[] userCertificate,
183 byte[] userCertificateChain) {
184 checkSystemCaller();
185 if (!mKeyStore.isUnlocked()) {
186 Log.e(TAG, "Keystore is " + mKeyStore.state().toString() + ". Credentials cannot"
187 + " be installed until device is unlocked");
188 return false;
189 }
190
191 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate,
192 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) {
193 Log.e(TAG, "Failed to import user certificate " + userCertificate);
194 return false;
195 }
196
197 if (userCertificateChain != null && userCertificateChain.length > 0) {
198 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain,
199 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) {
200 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain);
201 if (!mKeyStore.delete(Credentials.USER_CERTIFICATE + alias)) {
202 Log.e(TAG, "Failed to clean up key chain after certificate chain"
203 + " importing failed");
204 }
205 return false;
206 }
207 } else {
208 if (!mKeyStore.delete(Credentials.CA_CERTIFICATE + alias)) {
209 Log.e(TAG, "Failed to remove CA certificate chain for alias " + alias);
210 }
211 }
212 broadcastKeychainChange();
213 broadcastLegacyStorageChange();
214 return true;
215 }
216
Eran Messeri1223b5f2017-11-08 18:47:40 +0000217 private void validateAlias(String alias) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700218 if (alias == null) {
219 throw new NullPointerException("alias == null");
220 }
Eran Messeri1223b5f2017-11-08 18:47:40 +0000221 }
222
223 private void validateKeyStoreState() {
Kenny Root4ff22962013-02-14 10:17:06 -0800224 if (!mKeyStore.isUnlocked()) {
Nick Kralevichc8b04632012-05-21 15:13:07 -0700225 throw new IllegalStateException("keystore is "
226 + mKeyStore.state().toString());
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700227 }
Eran Messeri1223b5f2017-11-08 18:47:40 +0000228 }
229
230 private void checkArgs(String alias) {
231 validateAlias(alias);
232 validateKeyStoreState();
Nick Kralevichc8b04632012-05-21 15:13:07 -0700233
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700234 final int callingUid = getCallingUid();
Eran Messeri5844b632017-11-03 10:28:34 +0000235 if (!mGrantsDb.hasGrant(callingUid, alias)) {
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700236 throw new IllegalStateException("uid " + callingUid
237 + " doesn't have permission to access the requested alias");
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700238 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700239 }
240
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100241 @Override public String installCaCertificate(byte[] caCertificate) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700242 checkCertInstallerOrSystemCaller();
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100243 final String alias;
Brian Carlstroma58db542011-05-11 23:02:20 -0700244 try {
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100245 final X509Certificate cert = parseCertificate(caCertificate);
Brian Carlstroma58db542011-05-11 23:02:20 -0700246 synchronized (mTrustedCertificateStore) {
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100247 mTrustedCertificateStore.installCertificate(cert);
248 alias = mTrustedCertificateStore.getCertificateAlias(cert);
Brian Carlstroma58db542011-05-11 23:02:20 -0700249 }
250 } catch (IOException e) {
251 throw new IllegalStateException(e);
252 } catch (CertificateException e) {
253 throw new IllegalStateException(e);
254 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700255 broadcastLegacyStorageChange();
256 broadcastTrustStoreChange();
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100257 return alias;
Brian Carlstroma58db542011-05-11 23:02:20 -0700258 }
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700259
Rubin Xu8714f062016-03-23 12:37:10 +0000260 /**
261 * Install a key pair to the keystore.
262 *
263 * @param privateKey The private key associated with the client certificate
264 * @param userCertificate The client certificate to be installed
265 * @param userCertificateChain The rest of the chain for the client certificate
266 * @param alias The alias under which the key pair is installed
267 * @return Whether the operation succeeded or not.
268 */
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100269 @Override public boolean installKeyPair(byte[] privateKey, byte[] userCertificate,
Rubin Xu8714f062016-03-23 12:37:10 +0000270 byte[] userCertificateChain, String alias) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100271 checkCertInstallerOrSystemCaller();
Robin Lee8847b122015-07-27 12:50:28 +0100272 if (!mKeyStore.isUnlocked()) {
273 Log.e(TAG, "Keystore is " + mKeyStore.state().toString() + ". Credentials cannot"
274 + " be installed until device is unlocked");
275 return false;
276 }
Robin Leeba755b12016-02-24 15:27:43 +0000277 if (!removeKeyPair(alias)) {
278 return false;
279 }
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100280 if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, privateKey, -1,
281 KeyStore.FLAG_ENCRYPTED)) {
282 Log.e(TAG, "Failed to import private key " + alias);
283 return false;
284 }
285 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, -1,
286 KeyStore.FLAG_ENCRYPTED)) {
287 Log.e(TAG, "Failed to import user certificate " + userCertificate);
Alex Klyubin44c777b2015-06-08 09:46:15 -0700288 if (!mKeyStore.delete(Credentials.USER_PRIVATE_KEY + alias)) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100289 Log.e(TAG, "Failed to delete private key after certificate importing failed");
290 }
291 return false;
292 }
Rubin Xu8714f062016-03-23 12:37:10 +0000293 if (userCertificateChain != null && userCertificateChain.length > 0) {
294 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, -1,
295 KeyStore.FLAG_ENCRYPTED)) {
296 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain);
297 if (!removeKeyPair(alias)) {
298 Log.e(TAG, "Failed to clean up key chain after certificate chain"
299 + " importing failed");
300 }
301 return false;
302 }
303 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700304 broadcastKeychainChange();
305 broadcastLegacyStorageChange();
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100306 return true;
307 }
308
Robin Leef44a5192015-08-03 17:18:02 +0100309 @Override public boolean removeKeyPair(String alias) {
310 checkCertInstallerOrSystemCaller();
Robin Leeba755b12016-02-24 15:27:43 +0000311 if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
312 return false;
313 }
Eran Messerid0bcac82017-11-20 11:55:31 +0000314 mGrantsDb.removeAliasInformation(alias);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700315 broadcastKeychainChange();
316 broadcastLegacyStorageChange();
Robin Leeba755b12016-02-24 15:27:43 +0000317 return true;
Robin Leef44a5192015-08-03 17:18:02 +0100318 }
319
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700320 private X509Certificate parseCertificate(byte[] bytes) throws CertificateException {
321 CertificateFactory cf = CertificateFactory.getInstance("X.509");
322 return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes));
323 }
324
Brian Carlstroma58db542011-05-11 23:02:20 -0700325 @Override public boolean reset() {
326 // only Settings should be able to reset
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700327 checkSystemCaller();
Eran Messerid0bcac82017-11-20 11:55:31 +0000328 mGrantsDb.removeAllAliasesInformation();
Brian Carlstroma58db542011-05-11 23:02:20 -0700329 boolean ok = true;
Brian Carlstroma58db542011-05-11 23:02:20 -0700330 synchronized (mTrustedCertificateStore) {
331 // delete user-installed CA certs
332 for (String alias : mTrustedCertificateStore.aliases()) {
333 if (TrustedCertificateStore.isUser(alias)) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700334 if (!deleteCertificateEntry(alias)) {
Brian Carlstroma58db542011-05-11 23:02:20 -0700335 ok = false;
336 }
337 }
338 }
Brian Carlstroma58db542011-05-11 23:02:20 -0700339 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700340 broadcastTrustStoreChange();
Chad Brubaker8df30b52017-03-10 13:02:48 -0800341 broadcastKeychainChange();
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700342 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800343 return ok;
Brian Carlstroma58db542011-05-11 23:02:20 -0700344 }
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700345
346 @Override public boolean deleteCaCertificate(String alias) {
347 // only Settings should be able to delete
348 checkSystemCaller();
Selim Gurun39e36e52012-02-14 10:50:42 -0800349 boolean ok = true;
350 synchronized (mTrustedCertificateStore) {
351 ok = deleteCertificateEntry(alias);
352 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700353 broadcastTrustStoreChange();
354 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800355 return ok;
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700356 }
357
358 private boolean deleteCertificateEntry(String alias) {
359 try {
360 mTrustedCertificateStore.deleteCertificateEntry(alias);
361 return true;
362 } catch (IOException e) {
363 Log.w(TAG, "Problem removing CA certificate " + alias, e);
364 return false;
365 } catch (CertificateException e) {
366 Log.w(TAG, "Problem removing CA certificate " + alias, e);
367 return false;
368 }
369 }
370
371 private void checkCertInstallerOrSystemCaller() {
372 String actual = checkCaller("com.android.certinstaller");
373 if (actual == null) {
374 return;
375 }
376 checkSystemCaller();
377 }
378 private void checkSystemCaller() {
379 String actual = checkCaller("android.uid.system:1000");
380 if (actual != null) {
381 throw new IllegalStateException(actual);
382 }
383 }
384 /**
385 * Returns null if actually caller is expected, otherwise return bad package to report
386 */
387 private String checkCaller(String expectedPackage) {
388 String actualPackage = getPackageManager().getNameForUid(getCallingUid());
389 return (!expectedPackage.equals(actualPackage)) ? actualPackage : null;
390 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700391
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700392 @Override public boolean hasGrant(int uid, String alias) {
393 checkSystemCaller();
Eran Messeri5844b632017-11-03 10:28:34 +0000394 return mGrantsDb.hasGrant(uid, alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700395 }
396
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700397 @Override public void setGrant(int uid, String alias, boolean value) {
398 checkSystemCaller();
Eran Messeri5844b632017-11-03 10:28:34 +0000399 mGrantsDb.setGrant(uid, alias, value);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700400 broadcastPermissionChange(uid, alias, value);
401 broadcastLegacyStorageChange();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700402 }
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100403
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100404 @Override
Robin Lee7e9d0452017-02-20 20:57:41 +0000405 public StringParceledListSlice getUserCaAliases() {
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100406 synchronized (mTrustedCertificateStore) {
Robin Lee7e9d0452017-02-20 20:57:41 +0000407 return new StringParceledListSlice(new ArrayList<String>(
408 mTrustedCertificateStore.userAliases()));
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100409 }
410 }
411
412 @Override
Robin Lee7e9d0452017-02-20 20:57:41 +0000413 public StringParceledListSlice getSystemCaAliases() {
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100414 synchronized (mTrustedCertificateStore) {
Robin Lee7e9d0452017-02-20 20:57:41 +0000415 return new StringParceledListSlice(new ArrayList<String>(
416 mTrustedCertificateStore.allSystemAliases()));
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100417 }
418 }
419
420 @Override
421 public boolean containsCaAlias(String alias) {
422 return mTrustedCertificateStore.containsAlias(alias);
423 }
424
425 @Override
426 public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) {
427 synchronized (mTrustedCertificateStore) {
428 X509Certificate certificate = (X509Certificate) mTrustedCertificateStore
429 .getCertificate(alias, includeDeletedSystem);
430 if (certificate == null) {
431 Log.w(TAG, "Could not find CA certificate " + alias);
432 return null;
433 }
434 try {
435 return certificate.getEncoded();
436 } catch (CertificateEncodingException e) {
437 Log.w(TAG, "Error while encoding CA certificate " + alias);
438 return null;
439 }
440 }
441 }
442
443 @Override
444 public List<String> getCaCertificateChainAliases(String rootAlias,
445 boolean includeDeletedSystem) {
446 synchronized (mTrustedCertificateStore) {
447 X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate(
448 rootAlias, includeDeletedSystem);
449 try {
450 List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain(
451 root);
452 List<String> aliases = new ArrayList<String>(chain.size());
453 final int n = chain.size();
454 for (int i = 0; i < n; ++i) {
455 String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i),
456 true);
457 if (alias != null) {
458 aliases.add(alias);
459 }
460 }
461 return aliases;
462 } catch (CertificateException e) {
463 Log.w(TAG, "Error retrieving cert chain for root " + rootAlias);
464 return Collections.emptyList();
465 }
466 }
467 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700468 };
469
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700470 @Override public IBinder onBind(Intent intent) {
Brian Carlstrom7037b732011-06-30 15:04:49 -0700471 if (IKeyChainService.class.getName().equals(intent.getAction())) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700472 return mIKeyChainService;
473 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700474 return null;
475 }
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700476
477 @Override
478 protected void onHandleIntent(final Intent intent) {
479 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
Eran Messeri5844b632017-11-03 10:28:34 +0000480 mGrantsDb.purgeOldGrants(getPackageManager());
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700481 }
482 }
Selim Gurun39e36e52012-02-14 10:50:42 -0800483
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700484 private void broadcastLegacyStorageChange() {
Selim Gurun39e36e52012-02-14 10:50:42 -0800485 Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700486 BroadcastOptions opts = BroadcastOptions.makeBasic();
Chad Brubaker04028072016-07-08 10:48:54 -0700487 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.N_MR1);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700488 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()), null, opts.toBundle());
Selim Gurun39e36e52012-02-14 10:50:42 -0800489 }
490
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700491 private void broadcastKeychainChange() {
492 Intent intent = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700493 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700494 }
495
496 private void broadcastTrustStoreChange() {
497 Intent intent = new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700498 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700499 }
500
501 private void broadcastPermissionChange(int uid, String alias, boolean access) {
502 // Since the permission change only impacts one uid only send to that uid's packages.
503 final PackageManager packageManager = getPackageManager();
504 String[] packages = packageManager.getPackagesForUid(uid);
505 if (packages == null) {
506 return;
507 }
508 for (String pckg : packages) {
509 Intent intent = new Intent(KeyChain.ACTION_KEY_ACCESS_CHANGED);
510 intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, alias);
511 intent.putExtra(KeyChain.EXTRA_KEY_ACCESSIBLE, access);
512 intent.setPackage(pckg);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700513 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700514 }
515 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700516}