13e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom/* 23e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Copyright (C) 2011 The Android Open Source Project 33e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * 43e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 53e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * you may not use this file except in compliance with the License. 63e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * You may obtain a copy of the License at 73e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * 83e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 93e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * 103e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Unless required by applicable law or agreed to in writing, software 113e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 123e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * See the License for the specific language governing permissions and 143e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * limitations under the License. 153e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom */ 163e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 173e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrompackage com.android.keychain; 183e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 19fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.app.IntentService; 20fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.content.ContentValues; 213e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.content.Context; 223e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.content.Intent; 23fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.content.pm.PackageManager; 24fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.Cursor; 25fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.DatabaseUtils; 26fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.sqlite.SQLiteDatabase; 27fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper; 286f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Rootimport android.os.Binder; 293e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.os.IBinder; 306f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Rootimport android.os.Process; 313e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.security.Credentials; 323e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.security.IKeyChainService; 3339e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurunimport android.security.KeyChain; 343e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.security.KeyStore; 353e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.util.Log; 363e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.io.ByteArrayInputStream; 37a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstromimport java.io.IOException; 383e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.CertificateException; 393e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.CertificateFactory; 403e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.X509Certificate; 41fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 42a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstromimport org.apache.harmony.xnet.provider.jsse.TrustedCertificateStore; 433e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 44fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanapublic class KeyChainService extends IntentService { 4539e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun 46fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String TAG = "KeyChain"; 47fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 48fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String DATABASE_NAME = "grants.db"; 49fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final int DATABASE_VERSION = 1; 50fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String TABLE_GRANTS = "grants"; 51fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String GRANTS_ALIAS = "alias"; 52fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String GRANTS_GRANTEE_UID = "uid"; 533e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 54fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana /** created in onCreate(), closed in onDestroy() */ 55fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public DatabaseHelper mDatabaseHelper; 563e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 57fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String SELECTION_COUNT_OF_MATCHING_GRANTS = 58fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana "SELECT COUNT(*) FROM " + TABLE_GRANTS 59fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + " WHERE " + GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?"; 603e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 61fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String SELECT_GRANTS_BY_UID_AND_ALIAS = 62fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?"; 63fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 64fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String SELECTION_GRANTS_BY_UID = GRANTS_GRANTEE_UID + "=?"; 65fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 66fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public KeyChainService() { 67fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana super(KeyChainService.class.getSimpleName()); 68fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 693e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 703e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom @Override public void onCreate() { 713e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom super.onCreate(); 72fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana mDatabaseHelper = new DatabaseHelper(this); 733e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 743e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 75fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 76fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public void onDestroy() { 77fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana super.onDestroy(); 78fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana mDatabaseHelper.close(); 79fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana mDatabaseHelper = null; 80fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 813e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 82fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() { 833e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom private final KeyStore mKeyStore = KeyStore.getInstance(); 84a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom private final TrustedCertificateStore mTrustedCertificateStore 85a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom = new TrustedCertificateStore(); 863e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 876f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root @Override 886f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root public String requestPrivateKey(String alias) { 896f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root checkArgs(alias); 906f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root 916f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias; 926f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root final int uid = Binder.getCallingUid(); 936f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root if (!mKeyStore.grant(keystoreAlias, uid)) { 946f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root return null; 956f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root } 966f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root 976f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root final StringBuilder sb = new StringBuilder(); 986f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root sb.append(Process.SYSTEM_UID); 996f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root sb.append('_'); 1006f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root sb.append(keystoreAlias); 1016f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root 1026f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root return sb.toString(); 1033e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1043e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 105fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public byte[] getCertificate(String alias) { 1066f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root checkArgs(alias); 1076f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root return mKeyStore.get(Credentials.USER_CERTIFICATE + alias); 1083e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1093e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 1106f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root private void checkArgs(String alias) { 1113e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom if (alias == null) { 1123e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom throw new NullPointerException("alias == null"); 1133e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1143e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom if (!isKeyStoreUnlocked()) { 115c8b0463643df1f1a4035d641e155f5e1cef8e1b0Nick Kralevich throw new IllegalStateException("keystore is " 116c8b0463643df1f1a4035d641e155f5e1cef8e1b0Nick Kralevich + mKeyStore.state().toString()); 1173e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 118c8b0463643df1f1a4035d641e155f5e1cef8e1b0Nick Kralevich 119fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final int callingUid = getCallingUid(); 120fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (!hasGrantInternal(mDatabaseHelper.getReadableDatabase(), callingUid, alias)) { 121fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana throw new IllegalStateException("uid " + callingUid 122fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + " doesn't have permission to access the requested alias"); 1233e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1243e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1253e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 1265aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom private boolean isKeyStoreUnlocked() { 127e3b3390d3b1c96097c8e7cbd4c0eb51715677739Brian Carlstrom return (mKeyStore.state() == KeyStore.State.UNLOCKED); 1283e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 129a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom 130a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom @Override public void installCaCertificate(byte[] caCertificate) { 13143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkCertInstallerOrSystemCaller(); 132a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom try { 133a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom synchronized (mTrustedCertificateStore) { 134a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom mTrustedCertificateStore.installCertificate(parseCertificate(caCertificate)); 135a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 136a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } catch (IOException e) { 137a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom throw new IllegalStateException(e); 138a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } catch (CertificateException e) { 139a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom throw new IllegalStateException(e); 140a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 14139e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 142a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 1435aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom 1445aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom private X509Certificate parseCertificate(byte[] bytes) throws CertificateException { 1455aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom CertificateFactory cf = CertificateFactory.getInstance("X.509"); 1465aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes)); 1475aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom } 1485aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom 149a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom @Override public boolean reset() { 150a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom // only Settings should be able to reset 15143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkSystemCaller(); 152fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana removeAllGrants(mDatabaseHelper.getWritableDatabase()); 153a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom boolean ok = true; 154a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom synchronized (mTrustedCertificateStore) { 155a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom // delete user-installed CA certs 156a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom for (String alias : mTrustedCertificateStore.aliases()) { 157a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom if (TrustedCertificateStore.isUser(alias)) { 15843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom if (!deleteCertificateEntry(alias)) { 159a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom ok = false; 160a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 161a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 162a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 163a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 16439e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 16539e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun return ok; 166a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 16743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom 16843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom @Override public boolean deleteCaCertificate(String alias) { 16943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom // only Settings should be able to delete 17043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkSystemCaller(); 17139e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun boolean ok = true; 17239e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun synchronized (mTrustedCertificateStore) { 17339e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun ok = deleteCertificateEntry(alias); 17439e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun } 17539e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 17639e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun return ok; 17743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 17843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom 17943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private boolean deleteCertificateEntry(String alias) { 18043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom try { 18143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom mTrustedCertificateStore.deleteCertificateEntry(alias); 18243f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return true; 18343f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } catch (IOException e) { 18443f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom Log.w(TAG, "Problem removing CA certificate " + alias, e); 18543f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return false; 18643f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } catch (CertificateException e) { 18743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom Log.w(TAG, "Problem removing CA certificate " + alias, e); 18843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return false; 18943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 19043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 19143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom 19243f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private void checkCertInstallerOrSystemCaller() { 19343f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom String actual = checkCaller("com.android.certinstaller"); 19443f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom if (actual == null) { 19543f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return; 19643f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 19743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkSystemCaller(); 19843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 19943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private void checkSystemCaller() { 20043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom String actual = checkCaller("android.uid.system:1000"); 20143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom if (actual != null) { 20243f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom throw new IllegalStateException(actual); 20343f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 20443f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 20543f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom /** 20643f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom * Returns null if actually caller is expected, otherwise return bad package to report 20743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom */ 20843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private String checkCaller(String expectedPackage) { 20943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom String actualPackage = getPackageManager().getNameForUid(getCallingUid()); 21043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return (!expectedPackage.equals(actualPackage)) ? actualPackage : null; 21143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 2123e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 213fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public boolean hasGrant(int uid, String alias) { 214fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana checkSystemCaller(); 215fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana return hasGrantInternal(mDatabaseHelper.getReadableDatabase(), uid, alias); 2163e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 2173e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 218fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public void setGrant(int uid, String alias, boolean value) { 219fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana checkSystemCaller(); 220fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana setGrantInternal(mDatabaseHelper.getWritableDatabase(), uid, alias, value); 22139e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 2223e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 223fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana }; 2243e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 225fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private boolean hasGrantInternal(final SQLiteDatabase db, final int uid, final String alias) { 226fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final long numMatches = DatabaseUtils.longForQuery(db, SELECTION_COUNT_OF_MATCHING_GRANTS, 227fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{String.valueOf(uid), alias}); 228fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana return numMatches > 0; 229fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 2303e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 231fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private void setGrantInternal(final SQLiteDatabase db, 232fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final int uid, final String alias, final boolean value) { 233fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (value) { 234fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (!hasGrantInternal(db, uid, alias)) { 235fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final ContentValues values = new ContentValues(); 236fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana values.put(GRANTS_ALIAS, alias); 237fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana values.put(GRANTS_GRANTEE_UID, uid); 238fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.insert(TABLE_GRANTS, GRANTS_ALIAS, values); 239fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 240fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } else { 241fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.delete(TABLE_GRANTS, SELECT_GRANTS_BY_UID_AND_ALIAS, 242fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{String.valueOf(uid), alias}); 2433e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 244fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 2453e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 246fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private void removeAllGrants(final SQLiteDatabase db) { 247fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.delete(TABLE_GRANTS, null /* whereClause */, null /* whereArgs */); 248fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 2493e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 250fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private class DatabaseHelper extends SQLiteOpenHelper { 251fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public DatabaseHelper(Context context) { 252fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana super(context, DATABASE_NAME, null /* CursorFactory */, DATABASE_VERSION); 2533e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 2543e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 255fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 256fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public void onCreate(final SQLiteDatabase db) { 257fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( " 258fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + GRANTS_ALIAS + " STRING NOT NULL, " 259fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, " 260fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + "UNIQUE (" + GRANTS_ALIAS + "," + GRANTS_GRANTEE_UID + "))"); 2613e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 2623e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 263fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 264fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public void onUpgrade(final SQLiteDatabase db, int oldVersion, final int newVersion) { 265fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion); 2663e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 267fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (oldVersion == 1) { 268fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana // the first upgrade step goes here 269fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana oldVersion++; 2703e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 2717037b73962c34e884467d3d4a871ecdab9797fc3Brian Carlstrom } 272fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 273fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 274fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public IBinder onBind(Intent intent) { 2757037b73962c34e884467d3d4a871ecdab9797fc3Brian Carlstrom if (IKeyChainService.class.getName().equals(intent.getAction())) { 2763e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom return mIKeyChainService; 2773e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 2783e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom return null; 2793e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 280fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 281fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 282fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana protected void onHandleIntent(final Intent intent) { 283fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { 284fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana purgeOldGrants(); 285fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 286fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 287fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 288fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private void purgeOldGrants() { 289fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final PackageManager packageManager = getPackageManager(); 290fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); 291fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana Cursor cursor = null; 292fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.beginTransaction(); 293fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana try { 294fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana cursor = db.query(TABLE_GRANTS, 295fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{GRANTS_GRANTEE_UID}, null, null, GRANTS_GRANTEE_UID, null, null); 296fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana while (cursor.moveToNext()) { 297fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final int uid = cursor.getInt(0); 298fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final boolean packageExists = packageManager.getPackagesForUid(uid) != null; 299fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (packageExists) { 300fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana continue; 301fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 302fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana Log.d(TAG, "deleting grants for UID " + uid 303fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + " because its package is no longer installed"); 304fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.delete(TABLE_GRANTS, SELECTION_GRANTS_BY_UID, 305fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{Integer.toString(uid)}); 306fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 307fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.setTransactionSuccessful(); 308fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } finally { 309fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (cursor != null) { 310fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana cursor.close(); 311fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 312fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.endTransaction(); 313fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 314fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 31539e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun 31639e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun private void broadcastStorageChange() { 31739e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED); 31839e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun sendBroadcast(intent); 31939e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun } 32039e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun 3213e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom} 322