blob: e109d6b3bd80fc8622dd19c391925c9c120ddd36 [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
Pavel Grafov6e0960b2018-01-19 12:27:35 +000019import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED;
20import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED;
21
Chad Brubaker2099a7d2016-05-02 13:13:23 -070022import android.app.BroadcastOptions;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070023import android.app.IntentService;
Pavel Grafov6e0960b2018-01-19 12:27:35 +000024import android.app.admin.SecurityLog;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070025import android.content.Context;
26import android.content.Intent;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070027import android.content.pm.PackageManager;
Robin Lee7e9d0452017-02-20 20:57:41 +000028import android.content.pm.StringParceledListSlice;
Kenny Root6f1f03b2012-03-08 10:30:39 -080029import android.os.Binder;
Chad Brubaker2099a7d2016-05-02 13:13:23 -070030import android.os.Build;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070031import android.os.IBinder;
Robin Lee93772c32014-09-02 14:53:50 +010032import android.os.UserHandle;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070033import android.security.Credentials;
34import android.security.IKeyChainService;
Selim Gurun39e36e52012-02-14 10:50:42 -080035import android.security.KeyChain;
Pavel Grafov6e0960b2018-01-19 12:27:35 +000036import android.security.KeyStore;
Eran Messeri50ebe3f2017-12-11 16:58:33 +000037import android.security.keymaster.KeymasterArguments;
38import android.security.keymaster.KeymasterCertificateChain;
Eran Messeri241450c2017-12-21 20:58:41 +000039import android.security.keystore.AttestationUtils;
40import android.security.keystore.DeviceIdAttestationException;
Eran Messeri6d469272017-11-15 05:55:28 +000041import android.security.keystore.KeyGenParameterSpec;
42import android.security.keystore.ParcelableKeyGenParameterSpec;
43import android.text.TextUtils;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070044import android.util.Log;
Pavel Grafov6e0960b2018-01-19 12:27:35 +000045
46import com.android.internal.annotations.VisibleForTesting;
Eran Messeri5844b632017-11-03 10:28:34 +000047import com.android.keychain.internal.GrantsDatabase;
Pavel Grafov6e0960b2018-01-19 12:27:35 +000048import com.android.org.conscrypt.TrustedCertificateStore;
49
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070050import java.io.ByteArrayInputStream;
Brian Carlstroma58db542011-05-11 23:02:20 -070051import java.io.IOException;
Eran Messeri6d469272017-11-15 05:55:28 +000052import java.security.InvalidAlgorithmParameterException;
53import java.security.KeyPair;
54import java.security.KeyPairGenerator;
55import java.security.NoSuchAlgorithmException;
56import java.security.NoSuchProviderException;
Pavel Grafov6e0960b2018-01-19 12:27:35 +000057import java.security.cert.Certificate;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010058import java.security.cert.CertificateEncodingException;
Pavel Grafov6e0960b2018-01-19 12:27:35 +000059import java.security.cert.CertificateException;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070060import java.security.cert.CertificateFactory;
61import java.security.cert.X509Certificate;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010062import java.util.ArrayList;
63import java.util.Collections;
Pavel Grafov6e0960b2018-01-19 12:27:35 +000064import java.util.List;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070065
Pavel Grafov6e0960b2018-01-19 12:27:35 +000066import javax.security.auth.x500.X500Principal;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070067
Fred Quintanafb2e18e2011-07-13 14:54:05 -070068public class KeyChainService extends IntentService {
Selim Gurun39e36e52012-02-14 10:50:42 -080069
Fred Quintanafb2e18e2011-07-13 14:54:05 -070070 private static final String TAG = "KeyChain";
Pavel Grafov8b7af342018-02-01 18:48:24 +000071 private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
72 private static final String SYSTEM_PACKAGE = "android.uid.system:1000";
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070073
Fred Quintanafb2e18e2011-07-13 14:54:05 -070074 /** created in onCreate(), closed in onDestroy() */
Pavel Grafov6e0960b2018-01-19 12:27:35 +000075 private GrantsDatabase mGrantsDb;
76 private Injector mInjector;
Robin Leeba755b12016-02-24 15:27:43 +000077
Fred Quintanafb2e18e2011-07-13 14:54:05 -070078 public KeyChainService() {
79 super(KeyChainService.class.getSimpleName());
Pavel Grafov6e0960b2018-01-19 12:27:35 +000080 mInjector = new Injector();
Fred Quintanafb2e18e2011-07-13 14:54:05 -070081 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070082
83 @Override public void onCreate() {
84 super.onCreate();
Eran Messeri5844b632017-11-03 10:28:34 +000085 mGrantsDb = new GrantsDatabase(this);
Fred Quintanafb2e18e2011-07-13 14:54:05 -070086 }
87
88 @Override
89 public void onDestroy() {
90 super.onDestroy();
Eran Messeri5844b632017-11-03 10:28:34 +000091 mGrantsDb.destroy();
92 mGrantsDb = null;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070093 }
94
95 private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070096 private final KeyStore mKeyStore = KeyStore.getInstance();
Brian Carlstroma58db542011-05-11 23:02:20 -070097 private final TrustedCertificateStore mTrustedCertificateStore
98 = new TrustedCertificateStore();
Eran Messeri241450c2017-12-21 20:58:41 +000099 private final Context mContext = KeyChainService.this;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700100
Kenny Root6f1f03b2012-03-08 10:30:39 -0800101 @Override
102 public String requestPrivateKey(String alias) {
103 checkArgs(alias);
104
105 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias;
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000106 final int uid = mInjector.getCallingUid();
Janis Danisevskisc394aea2017-06-07 10:20:45 -0700107 return mKeyStore.grant(keystoreAlias, uid);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700108 }
109
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700110 @Override public byte[] getCertificate(String alias) {
Kenny Root6f1f03b2012-03-08 10:30:39 -0800111 checkArgs(alias);
112 return mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700113 }
114
Rubin Xu8714f062016-03-23 12:37:10 +0000115 @Override public byte[] getCaCertificates(String alias) {
116 checkArgs(alias);
117 return mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
118 }
119
Eran Messeri1223b5f2017-11-08 18:47:40 +0000120 @Override public boolean isUserSelectable(String alias) {
121 validateAlias(alias);
122 return mGrantsDb.isUserSelectable(alias);
123 }
124
125 @Override public void setUserSelectable(String alias, boolean isUserSelectable) {
126 validateAlias(alias);
127 checkSystemCaller();
128 mGrantsDb.setIsUserSelectable(alias, isUserSelectable);
129 }
130
Eran Messeria5125142018-03-26 16:43:07 +0100131 @Override public int generateKeyPair(
Eran Messeri6d469272017-11-15 05:55:28 +0000132 String algorithm, ParcelableKeyGenParameterSpec parcelableSpec) {
133 checkSystemCaller();
134 final KeyGenParameterSpec spec = parcelableSpec.getSpec();
135 final String alias = spec.getKeystoreAlias();
136 // Validate the alias here to avoid relying on KeyGenParameterSpec c'tor preventing
137 // the creation of a KeyGenParameterSpec instance with a non-empty alias.
138 if (TextUtils.isEmpty(alias) || spec.getUid() != KeyStore.UID_SELF) {
139 Log.e(TAG, "Cannot generate key pair with empty alias or specified uid.");
Eran Messeria5125142018-03-26 16:43:07 +0100140 return KeyChain.KEY_GEN_MISSING_ALIAS;
Eran Messeri6d469272017-11-15 05:55:28 +0000141 }
142
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000143 if (spec.getAttestationChallenge() != null) {
144 Log.e(TAG, "Key generation request should not include an Attestation challenge.");
Eran Messeria5125142018-03-26 16:43:07 +0100145 return KeyChain.KEY_GEN_SUPERFLUOUS_ATTESTATION_CHALLENGE;
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000146 }
147
Eran Messeri6d469272017-11-15 05:55:28 +0000148 try {
149 KeyPairGenerator generator = KeyPairGenerator.getInstance(
150 algorithm, "AndroidKeyStore");
151 // Do not prepend USER_PRIVATE_KEY to the alias because
152 // AndroidKeyStoreKeyPairGeneratorSpi will helpfully prepend that in
153 // generateKeyPair.
154 generator.initialize(spec);
155 KeyPair kp = generator.generateKeyPair();
156 if (kp == null) {
157 Log.e(TAG, "Key generation failed.");
Eran Messeria5125142018-03-26 16:43:07 +0100158 return KeyChain.KEY_GEN_FAILURE;
Eran Messeri6d469272017-11-15 05:55:28 +0000159 }
Eran Messeria5125142018-03-26 16:43:07 +0100160 return KeyChain.KEY_GEN_SUCCESS;
Eran Messeri6d469272017-11-15 05:55:28 +0000161 } catch (NoSuchAlgorithmException e) {
162 Log.e(TAG, "Invalid algorithm requested", e);
Eran Messeria5125142018-03-26 16:43:07 +0100163 return KeyChain.KEY_GEN_NO_SUCH_ALGORITHM;
Eran Messeri6d469272017-11-15 05:55:28 +0000164 } catch (InvalidAlgorithmParameterException e) {
165 Log.e(TAG, "Invalid algorithm params", e);
Eran Messeria5125142018-03-26 16:43:07 +0100166 return KeyChain.KEY_GEN_INVALID_ALGORITHM_PARAMETERS;
Eran Messeri6d469272017-11-15 05:55:28 +0000167 } catch (NoSuchProviderException e) {
168 Log.e(TAG, "Could not find Keystore.", e);
Eran Messeria5125142018-03-26 16:43:07 +0100169 return KeyChain.KEY_GEN_NO_KEYSTORE_PROVIDER;
Eran Messeri6d469272017-11-15 05:55:28 +0000170 }
Eran Messeri6d469272017-11-15 05:55:28 +0000171 }
172
Eran Messeria5125142018-03-26 16:43:07 +0100173 @Override public int attestKey(
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000174 String alias, byte[] attestationChallenge,
Eran Messeri241450c2017-12-21 20:58:41 +0000175 int[] idAttestationFlags,
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000176 KeymasterCertificateChain attestationChain) {
177 checkSystemCaller();
178 validateAlias(alias);
179
180 if (attestationChallenge == null) {
181 Log.e(TAG, String.format("Missing attestation challenge for alias %s", alias));
Eran Messeria5125142018-03-26 16:43:07 +0100182 return KeyChain.KEY_ATTESTATION_MISSING_CHALLENGE;
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000183 }
184
Eran Messeri241450c2017-12-21 20:58:41 +0000185 final KeymasterArguments attestArgs;
186 try {
187 attestArgs = AttestationUtils.prepareAttestationArguments(
188 mContext, idAttestationFlags, attestationChallenge);
189 } catch (DeviceIdAttestationException e) {
190 Log.e(TAG, "Failed collecting attestation data", e);
Eran Messeria5125142018-03-26 16:43:07 +0100191 return KeyChain.KEY_ATTESTATION_CANNOT_COLLECT_DATA;
Eran Messeri241450c2017-12-21 20:58:41 +0000192 }
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000193 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias;
194 final int errorCode = mKeyStore.attestKey(keystoreAlias, attestArgs, attestationChain);
Eran Messeria5125142018-03-26 16:43:07 +0100195 if (errorCode != KeyStore.NO_ERROR) {
196 Log.e(TAG, String.format("Failure attesting for key %s: %d", alias, errorCode));
197 if (errorCode == KeyStore.CANNOT_ATTEST_IDS) {
198 return KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS;
199 } else {
200 // General failure, cannot discern which.
201 return KeyChain.KEY_ATTESTATION_FAILURE;
202 }
203 }
204
205 return KeyChain.KEY_ATTESTATION_SUCCESS;
Eran Messeri50ebe3f2017-12-11 16:58:33 +0000206 }
207
Eran Messeri4b18d652017-12-11 12:32:25 +0000208 @Override public boolean setKeyPairCertificate(String alias, byte[] userCertificate,
209 byte[] userCertificateChain) {
210 checkSystemCaller();
211 if (!mKeyStore.isUnlocked()) {
212 Log.e(TAG, "Keystore is " + mKeyStore.state().toString() + ". Credentials cannot"
213 + " be installed until device is unlocked");
214 return false;
215 }
216
217 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate,
218 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) {
219 Log.e(TAG, "Failed to import user certificate " + userCertificate);
220 return false;
221 }
222
223 if (userCertificateChain != null && userCertificateChain.length > 0) {
224 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain,
225 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) {
226 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain);
227 if (!mKeyStore.delete(Credentials.USER_CERTIFICATE + alias)) {
228 Log.e(TAG, "Failed to clean up key chain after certificate chain"
229 + " importing failed");
230 }
231 return false;
232 }
233 } else {
234 if (!mKeyStore.delete(Credentials.CA_CERTIFICATE + alias)) {
235 Log.e(TAG, "Failed to remove CA certificate chain for alias " + alias);
236 }
237 }
238 broadcastKeychainChange();
239 broadcastLegacyStorageChange();
240 return true;
241 }
242
Eran Messeri1223b5f2017-11-08 18:47:40 +0000243 private void validateAlias(String alias) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700244 if (alias == null) {
245 throw new NullPointerException("alias == null");
246 }
Eran Messeri1223b5f2017-11-08 18:47:40 +0000247 }
248
249 private void validateKeyStoreState() {
Kenny Root4ff22962013-02-14 10:17:06 -0800250 if (!mKeyStore.isUnlocked()) {
Nick Kralevichc8b04632012-05-21 15:13:07 -0700251 throw new IllegalStateException("keystore is "
252 + mKeyStore.state().toString());
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700253 }
Eran Messeri1223b5f2017-11-08 18:47:40 +0000254 }
255
256 private void checkArgs(String alias) {
257 validateAlias(alias);
258 validateKeyStoreState();
Nick Kralevichc8b04632012-05-21 15:13:07 -0700259
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000260 final int callingUid = mInjector.getCallingUid();
Eran Messeri5844b632017-11-03 10:28:34 +0000261 if (!mGrantsDb.hasGrant(callingUid, alias)) {
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700262 throw new IllegalStateException("uid " + callingUid
263 + " doesn't have permission to access the requested alias");
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700264 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700265 }
266
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100267 @Override public String installCaCertificate(byte[] caCertificate) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700268 checkCertInstallerOrSystemCaller();
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100269 final String alias;
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000270 String subjectForAudit = null;
Brian Carlstroma58db542011-05-11 23:02:20 -0700271 try {
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100272 final X509Certificate cert = parseCertificate(caCertificate);
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000273 if (mInjector.isSecurityLoggingEnabled()) {
274 subjectForAudit =
275 cert.getSubjectX500Principal().getName(X500Principal.CANONICAL);
276 }
Brian Carlstroma58db542011-05-11 23:02:20 -0700277 synchronized (mTrustedCertificateStore) {
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100278 mTrustedCertificateStore.installCertificate(cert);
279 alias = mTrustedCertificateStore.getCertificateAlias(cert);
Brian Carlstroma58db542011-05-11 23:02:20 -0700280 }
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000281 } catch (IOException | CertificateException e) {
282 if (subjectForAudit != null) {
283 mInjector.writeSecurityEvent(
284 TAG_CERT_AUTHORITY_INSTALLED, 0 /*result*/, subjectForAudit);
285 }
Brian Carlstroma58db542011-05-11 23:02:20 -0700286 throw new IllegalStateException(e);
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000287 }
288 if (subjectForAudit != null) {
289 mInjector.writeSecurityEvent(
290 TAG_CERT_AUTHORITY_INSTALLED, 1 /*result*/, subjectForAudit);
Brian Carlstroma58db542011-05-11 23:02:20 -0700291 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700292 broadcastLegacyStorageChange();
293 broadcastTrustStoreChange();
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100294 return alias;
Brian Carlstroma58db542011-05-11 23:02:20 -0700295 }
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700296
Rubin Xu8714f062016-03-23 12:37:10 +0000297 /**
298 * Install a key pair to the keystore.
299 *
300 * @param privateKey The private key associated with the client certificate
301 * @param userCertificate The client certificate to be installed
302 * @param userCertificateChain The rest of the chain for the client certificate
303 * @param alias The alias under which the key pair is installed
304 * @return Whether the operation succeeded or not.
305 */
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100306 @Override public boolean installKeyPair(byte[] privateKey, byte[] userCertificate,
Rubin Xu8714f062016-03-23 12:37:10 +0000307 byte[] userCertificateChain, String alias) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100308 checkCertInstallerOrSystemCaller();
Robin Lee8847b122015-07-27 12:50:28 +0100309 if (!mKeyStore.isUnlocked()) {
310 Log.e(TAG, "Keystore is " + mKeyStore.state().toString() + ". Credentials cannot"
311 + " be installed until device is unlocked");
312 return false;
313 }
Robin Leeba755b12016-02-24 15:27:43 +0000314 if (!removeKeyPair(alias)) {
315 return false;
316 }
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100317 if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, privateKey, -1,
318 KeyStore.FLAG_ENCRYPTED)) {
319 Log.e(TAG, "Failed to import private key " + alias);
320 return false;
321 }
322 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, -1,
323 KeyStore.FLAG_ENCRYPTED)) {
324 Log.e(TAG, "Failed to import user certificate " + userCertificate);
Alex Klyubin44c777b2015-06-08 09:46:15 -0700325 if (!mKeyStore.delete(Credentials.USER_PRIVATE_KEY + alias)) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100326 Log.e(TAG, "Failed to delete private key after certificate importing failed");
327 }
328 return false;
329 }
Rubin Xu8714f062016-03-23 12:37:10 +0000330 if (userCertificateChain != null && userCertificateChain.length > 0) {
331 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, -1,
332 KeyStore.FLAG_ENCRYPTED)) {
333 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain);
334 if (!removeKeyPair(alias)) {
335 Log.e(TAG, "Failed to clean up key chain after certificate chain"
336 + " importing failed");
337 }
338 return false;
339 }
340 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700341 broadcastKeychainChange();
342 broadcastLegacyStorageChange();
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100343 return true;
344 }
345
Robin Leef44a5192015-08-03 17:18:02 +0100346 @Override public boolean removeKeyPair(String alias) {
347 checkCertInstallerOrSystemCaller();
Robin Leeba755b12016-02-24 15:27:43 +0000348 if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
349 return false;
350 }
Eran Messerid0bcac82017-11-20 11:55:31 +0000351 mGrantsDb.removeAliasInformation(alias);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700352 broadcastKeychainChange();
353 broadcastLegacyStorageChange();
Robin Leeba755b12016-02-24 15:27:43 +0000354 return true;
Robin Leef44a5192015-08-03 17:18:02 +0100355 }
356
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700357 private X509Certificate parseCertificate(byte[] bytes) throws CertificateException {
358 CertificateFactory cf = CertificateFactory.getInstance("X.509");
359 return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes));
360 }
361
Brian Carlstroma58db542011-05-11 23:02:20 -0700362 @Override public boolean reset() {
363 // only Settings should be able to reset
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700364 checkSystemCaller();
Eran Messerid0bcac82017-11-20 11:55:31 +0000365 mGrantsDb.removeAllAliasesInformation();
Brian Carlstroma58db542011-05-11 23:02:20 -0700366 boolean ok = true;
Brian Carlstroma58db542011-05-11 23:02:20 -0700367 synchronized (mTrustedCertificateStore) {
368 // delete user-installed CA certs
369 for (String alias : mTrustedCertificateStore.aliases()) {
370 if (TrustedCertificateStore.isUser(alias)) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700371 if (!deleteCertificateEntry(alias)) {
Brian Carlstroma58db542011-05-11 23:02:20 -0700372 ok = false;
373 }
374 }
375 }
Brian Carlstroma58db542011-05-11 23:02:20 -0700376 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700377 broadcastTrustStoreChange();
Chad Brubaker8df30b52017-03-10 13:02:48 -0800378 broadcastKeychainChange();
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700379 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800380 return ok;
Brian Carlstroma58db542011-05-11 23:02:20 -0700381 }
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700382
383 @Override public boolean deleteCaCertificate(String alias) {
384 // only Settings should be able to delete
385 checkSystemCaller();
Selim Gurun39e36e52012-02-14 10:50:42 -0800386 boolean ok = true;
387 synchronized (mTrustedCertificateStore) {
388 ok = deleteCertificateEntry(alias);
389 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700390 broadcastTrustStoreChange();
391 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800392 return ok;
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700393 }
394
395 private boolean deleteCertificateEntry(String alias) {
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000396 String subjectForAudit = null;
397 if (mInjector.isSecurityLoggingEnabled()) {
398 final Certificate cert = mTrustedCertificateStore.getCertificate(alias);
399 if (cert instanceof X509Certificate) {
400 subjectForAudit = ((X509Certificate) cert)
401 .getSubjectX500Principal().getName(X500Principal.CANONICAL);
402 }
403 }
404
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700405 try {
406 mTrustedCertificateStore.deleteCertificateEntry(alias);
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000407 if (subjectForAudit != null) {
408 mInjector.writeSecurityEvent(
409 TAG_CERT_AUTHORITY_REMOVED, 1 /*result*/, subjectForAudit);
410 }
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700411 return true;
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000412 } catch (IOException | CertificateException e) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700413 Log.w(TAG, "Problem removing CA certificate " + alias, e);
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000414 if (subjectForAudit != null) {
415 mInjector.writeSecurityEvent(
416 TAG_CERT_AUTHORITY_REMOVED, 0 /*result*/, subjectForAudit);
417 }
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700418 return false;
419 }
420 }
421
422 private void checkCertInstallerOrSystemCaller() {
Pavel Grafov8b7af342018-02-01 18:48:24 +0000423 final String caller = callingPackage();
424 if (!SYSTEM_PACKAGE.equals(caller) && !CERT_INSTALLER_PACKAGE.equals(caller)) {
425 throw new SecurityException("Not system or cert installer package: " + caller);
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700426 }
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700427 }
Pavel Grafov8b7af342018-02-01 18:48:24 +0000428
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700429 private void checkSystemCaller() {
Pavel Grafov8b7af342018-02-01 18:48:24 +0000430 final String caller = callingPackage();
431 if (!SYSTEM_PACKAGE.equals(caller)) {
432 throw new SecurityException("Not system package: " + caller);
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700433 }
434 }
Pavel Grafov8b7af342018-02-01 18:48:24 +0000435
436 private String callingPackage() {
437 return getPackageManager().getNameForUid(mInjector.getCallingUid());
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700438 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700439
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700440 @Override public boolean hasGrant(int uid, String alias) {
441 checkSystemCaller();
Eran Messeri5844b632017-11-03 10:28:34 +0000442 return mGrantsDb.hasGrant(uid, alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700443 }
444
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700445 @Override public void setGrant(int uid, String alias, boolean value) {
446 checkSystemCaller();
Eran Messeri5844b632017-11-03 10:28:34 +0000447 mGrantsDb.setGrant(uid, alias, value);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700448 broadcastPermissionChange(uid, alias, value);
449 broadcastLegacyStorageChange();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700450 }
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100451
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100452 @Override
Robin Lee7e9d0452017-02-20 20:57:41 +0000453 public StringParceledListSlice getUserCaAliases() {
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100454 synchronized (mTrustedCertificateStore) {
Robin Lee7e9d0452017-02-20 20:57:41 +0000455 return new StringParceledListSlice(new ArrayList<String>(
456 mTrustedCertificateStore.userAliases()));
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100457 }
458 }
459
460 @Override
Robin Lee7e9d0452017-02-20 20:57:41 +0000461 public StringParceledListSlice getSystemCaAliases() {
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100462 synchronized (mTrustedCertificateStore) {
Robin Lee7e9d0452017-02-20 20:57:41 +0000463 return new StringParceledListSlice(new ArrayList<String>(
464 mTrustedCertificateStore.allSystemAliases()));
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100465 }
466 }
467
468 @Override
469 public boolean containsCaAlias(String alias) {
470 return mTrustedCertificateStore.containsAlias(alias);
471 }
472
473 @Override
474 public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) {
475 synchronized (mTrustedCertificateStore) {
476 X509Certificate certificate = (X509Certificate) mTrustedCertificateStore
477 .getCertificate(alias, includeDeletedSystem);
478 if (certificate == null) {
479 Log.w(TAG, "Could not find CA certificate " + alias);
480 return null;
481 }
482 try {
483 return certificate.getEncoded();
484 } catch (CertificateEncodingException e) {
485 Log.w(TAG, "Error while encoding CA certificate " + alias);
486 return null;
487 }
488 }
489 }
490
491 @Override
492 public List<String> getCaCertificateChainAliases(String rootAlias,
493 boolean includeDeletedSystem) {
494 synchronized (mTrustedCertificateStore) {
495 X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate(
496 rootAlias, includeDeletedSystem);
497 try {
498 List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain(
499 root);
500 List<String> aliases = new ArrayList<String>(chain.size());
501 final int n = chain.size();
502 for (int i = 0; i < n; ++i) {
503 String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i),
504 true);
505 if (alias != null) {
506 aliases.add(alias);
507 }
508 }
509 return aliases;
510 } catch (CertificateException e) {
511 Log.w(TAG, "Error retrieving cert chain for root " + rootAlias);
512 return Collections.emptyList();
513 }
514 }
515 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700516 };
517
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700518 @Override public IBinder onBind(Intent intent) {
Brian Carlstrom7037b732011-06-30 15:04:49 -0700519 if (IKeyChainService.class.getName().equals(intent.getAction())) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700520 return mIKeyChainService;
521 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700522 return null;
523 }
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700524
525 @Override
526 protected void onHandleIntent(final Intent intent) {
527 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
Eran Messeri5844b632017-11-03 10:28:34 +0000528 mGrantsDb.purgeOldGrants(getPackageManager());
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700529 }
530 }
Selim Gurun39e36e52012-02-14 10:50:42 -0800531
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700532 private void broadcastLegacyStorageChange() {
Selim Gurun39e36e52012-02-14 10:50:42 -0800533 Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700534 BroadcastOptions opts = BroadcastOptions.makeBasic();
Chad Brubaker04028072016-07-08 10:48:54 -0700535 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.N_MR1);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700536 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()), null, opts.toBundle());
Selim Gurun39e36e52012-02-14 10:50:42 -0800537 }
538
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700539 private void broadcastKeychainChange() {
540 Intent intent = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700541 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700542 }
543
544 private void broadcastTrustStoreChange() {
545 Intent intent = new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700546 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700547 }
548
549 private void broadcastPermissionChange(int uid, String alias, boolean access) {
550 // Since the permission change only impacts one uid only send to that uid's packages.
551 final PackageManager packageManager = getPackageManager();
552 String[] packages = packageManager.getPackagesForUid(uid);
553 if (packages == null) {
554 return;
555 }
556 for (String pckg : packages) {
557 Intent intent = new Intent(KeyChain.ACTION_KEY_ACCESS_CHANGED);
558 intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, alias);
559 intent.putExtra(KeyChain.EXTRA_KEY_ACCESSIBLE, access);
560 intent.setPackage(pckg);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700561 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700562 }
563 }
Pavel Grafov6e0960b2018-01-19 12:27:35 +0000564
565 @VisibleForTesting
566 void setInjector(Injector injector) {
567 mInjector = injector;
568 }
569
570 /**
571 * Injector for mocking out dependencies in tests.
572 */
573 @VisibleForTesting
574 static class Injector {
575 public boolean isSecurityLoggingEnabled() {
576 return SecurityLog.isLoggingEnabled();
577 }
578
579 public void writeSecurityEvent(int tag, Object... payload) {
580 SecurityLog.writeEvent(tag, payload);
581 }
582
583 public int getCallingUid() {
584 return Binder.getCallingUid();
585 }
586 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700587}