Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dfdacaf2 authored by Kenny Root's avatar Kenny Root Committed by Android Git Automerger
Browse files

am bda3e26f: am 42457027: Merge changes I65f7a915,I32098dc0

* commit 'bda3e26f':
  KeyStore: add "migrate" command
  KeyStore: add API to uid versions
parents 3be79f32 bda3e26f
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -148,6 +148,10 @@ public interface IKeystoreService extends IInterface {
                    for (int i = 0; i < size; i++) {
                        _result[i] = _reply.readString();
                    }
                    int _ret = _reply.readInt();
                    if (_ret != 1) {
                        return null;
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
@@ -401,6 +405,25 @@ public interface IKeystoreService extends IInterface {
                }
                return _result;
            }

            @Override
            public int migrate(String name, int targetUid) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(name);
                    _data.writeInt(targetUid);
                    mRemote.transact(Stub.TRANSACTION_migrate, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        private static final String DESCRIPTOR = "android.security.keystore";
@@ -425,6 +448,7 @@ public interface IKeystoreService extends IInterface {
        static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17;
        static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
        static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
        static final int TRANSACTION_migrate = IBinder.FIRST_CALL_TRANSACTION + 20;

        /**
         * Cast an IBinder object into an IKeystoreService interface, generating
@@ -509,4 +533,6 @@ public interface IKeystoreService extends IInterface {
    public int ungrant(String name, int granteeUid) throws RemoteException;

    public long getmtime(String name) throws RemoteException;

    public int migrate(String name, int targetUid) throws RemoteException;
}
+25 −20
Original line number Diff line number Diff line
@@ -453,6 +453,7 @@ public class AndroidKeyStore extends KeyStoreSpi {
         * convention.
         */
        final String[] certAliases = mKeyStore.saw(Credentials.USER_CERTIFICATE);
        if (certAliases != null) {
            for (String alias : certAliases) {
                final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
                if (certBytes == null) {
@@ -466,12 +467,14 @@ public class AndroidKeyStore extends KeyStoreSpi {
                    return alias;
                }
            }
        }

        /*
         * Look at all the TrustedCertificateEntry types. Skip all the
         * PrivateKeyEntry we looked at above.
         */
        final String[] caAliases = mKeyStore.saw(Credentials.CA_CERTIFICATE);
        if (certAliases != null) {
            for (String alias : caAliases) {
                if (nonCaEntries.contains(alias)) {
                    continue;
@@ -482,11 +485,13 @@ public class AndroidKeyStore extends KeyStoreSpi {
                    continue;
                }

            final Certificate c = toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
                final Certificate c =
                        toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
                if (cert.equals(c)) {
                    return alias;
                }
            }
        }

        return null;
    }
+51 −14
Original line number Diff line number Diff line
@@ -87,42 +87,58 @@ public class KeyStore {
        }
    }

    public boolean put(String key, byte[] value) {
    public boolean put(String key, byte[] value, int uid) {
        try {
            return mBinder.insert(key, value, -1) == NO_ERROR;
            return mBinder.insert(key, value, uid) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public boolean delete(String key) {
    public boolean put(String key, byte[] value) {
        return put(key, value, -1);
    }

    public boolean delete(String key, int uid) {
        try {
            return mBinder.del(key, -1) == NO_ERROR;
            return mBinder.del(key, uid) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public boolean contains(String key) {
    public boolean delete(String key) {
        return delete(key, -1);
    }

    public boolean contains(String key, int uid) {
        try {
            return mBinder.exist(key, -1) == NO_ERROR;
            return mBinder.exist(key, uid) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public String[] saw(String prefix) {
    public boolean contains(String key) {
        return contains(key, -1);
    }

    public String[] saw(String prefix, int uid) {
        try {
            return mBinder.saw(prefix, -1);
            return mBinder.saw(prefix, uid);
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return null;
        }
    }

    public String[] saw(String prefix) {
        return saw(prefix, -1);
    }

    public boolean reset() {
        try {
            return mBinder.reset() == NO_ERROR;
@@ -169,24 +185,32 @@ public class KeyStore {
        }
    }

    public boolean generate(String key) {
    public boolean generate(String key, int uid) {
        try {
            return mBinder.generate(key, -1) == NO_ERROR;
            return mBinder.generate(key, uid) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public boolean importKey(String keyName, byte[] key) {
    public boolean generate(String key) {
        return generate(key, -1);
    }

    public boolean importKey(String keyName, byte[] key, int uid) {
        try {
            return mBinder.import_key(keyName, key, -1) == NO_ERROR;
            return mBinder.import_key(keyName, key, uid) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public boolean importKey(String keyName, byte[] key) {
        return importKey(keyName, key, -1);
    }

    public byte[] getPubkey(String key) {
        try {
            return mBinder.get_pubkey(key);
@@ -196,15 +220,19 @@ public class KeyStore {
        }
    }

    public boolean delKey(String key) {
    public boolean delKey(String key, int uid) {
        try {
            return mBinder.del_key(key, -1) == NO_ERROR;
            return mBinder.del_key(key, uid) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public boolean delKey(String key) {
        return delKey(key, -1);
    }

    public byte[] sign(String key, byte[] data) {
        try {
            return mBinder.sign(key, data);
@@ -259,6 +287,15 @@ public class KeyStore {
        }
    }

    public boolean migrate(String key, int uid) {
        try {
            return mBinder.migrate(key, uid) == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public int getLastError() {
        return mError;
    }
+3 −1
Original line number Diff line number Diff line
@@ -67,7 +67,9 @@ public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
        assertTrue(mAndroidKeyStore.password("1111"));
        assertTrue(mAndroidKeyStore.isUnlocked());

        assertEquals(0, mAndroidKeyStore.saw("").length);
        String[] aliases = mAndroidKeyStore.saw("");
        assertNotNull(aliases);
        assertEquals(0, aliases.length);

        mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME);
    }
+185 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.security;

import android.app.Activity;
import android.os.Process;
import android.security.KeyStore;
import android.test.ActivityUnitTestCase;
import android.test.AssertionFailedError;
@@ -128,7 +129,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
        super.tearDown();
    }

    public void teststate() throws Exception {
    public void testState() throws Exception {
        assertEquals(KeyStore.State.UNINITIALIZED, mKeyStore.state());
    }

@@ -154,6 +155,24 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
    }

    public void testPut_grantedUid_Wifi() throws Exception {
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
        mKeyStore.password(TEST_PASSWD);
        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    }

    public void testPut_ungrantedUid_Bluetooth() throws Exception {
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
        mKeyStore.password(TEST_PASSWD);
        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
    }

    public void testI18n() throws Exception {
        assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE));
        assertFalse(mKeyStore.contains(TEST_I18N_KEY));
@@ -167,22 +186,64 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
        mKeyStore.password(TEST_PASSWD);
        assertFalse(mKeyStore.delete(TEST_KEYNAME));

        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
        assertTrue(mKeyStore.delete(TEST_KEYNAME));
        assertNull(mKeyStore.get(TEST_KEYNAME));
    }

    public void testDelete_grantedUid_Wifi() throws Exception {
        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
        mKeyStore.password(TEST_PASSWD);
        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));

        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
        assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    }

    public void testDelete_ungrantedUid_Bluetooth() throws Exception {
        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
        mKeyStore.password(TEST_PASSWD);
        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));

        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
    }

    public void testContains() throws Exception {
        assertFalse(mKeyStore.contains(TEST_KEYNAME));

        mKeyStore.password(TEST_PASSWD);
        assertTrue(mKeyStore.password(TEST_PASSWD));
        assertFalse(mKeyStore.contains(TEST_KEYNAME));

        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
        assertTrue(mKeyStore.contains(TEST_KEYNAME));
    }

    public void testContains_grantedUid_Wifi() throws Exception {
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));

        assertTrue(mKeyStore.password(TEST_PASSWD));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));

        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    }

    public void testContains_grantedUid_Bluetooth() throws Exception {
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));

        assertTrue(mKeyStore.password(TEST_PASSWD));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));

        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
    }

    public void testSaw() throws Exception {
        String[] emptyResult = mKeyStore.saw(TEST_KEYNAME);
        assertNotNull(emptyResult);
@@ -198,6 +259,48 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
                     new HashSet(Arrays.asList(results)));
    }

    public void testSaw_ungrantedUid_Bluetooth() throws Exception {
        String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
        assertNull(results1);

        mKeyStore.password(TEST_PASSWD);
        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE);
        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE);

        String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
        assertNull(results2);
    }

    public void testSaw_grantedUid_Wifi() throws Exception {
        String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
        assertNotNull(results1);
        assertEquals(0, results1.length);

        mKeyStore.password(TEST_PASSWD);
        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID);
        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID);

        String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
        assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
                                               TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
                     new HashSet(Arrays.asList(results2)));
    }

    public void testSaw_grantedUid_Vpn() throws Exception {
        String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
        assertNotNull(results1);
        assertEquals(0, results1.length);

        mKeyStore.password(TEST_PASSWD);
        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID);
        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID);

        String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
        assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
                                               TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
                     new HashSet(Arrays.asList(results2)));
    }

    public void testLock() throws Exception {
        assertFalse(mKeyStore.lock());

@@ -239,17 +342,57 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
    }

    public void testGenerate_Success() throws Exception {
        mKeyStore.password(TEST_PASSWD);
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertTrue("Should be able to generate key when unlocked",
                mKeyStore.generate(TEST_KEYNAME));
        assertTrue(mKeyStore.contains(TEST_KEYNAME));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    }

    public void testGenerate_grantedUid_Wifi_Success() throws Exception {
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertTrue("Should be able to generate key when unlocked",
                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID));
        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME));
    }

    public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception {
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME));
    }

    public void testImport_Success() throws Exception {
        mKeyStore.password(TEST_PASSWD);
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertTrue("Should be able to import key when unlocked",
                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
        assertTrue(mKeyStore.contains(TEST_KEYNAME));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    }

    public void testImport_grantedUid_Wifi_Success() throws Exception {
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertTrue("Should be able to import key when unlocked",
                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.WIFI_UID));
        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME));
    }

    public void testImport_ungrantedUid_Bluetooth_Failure() throws Exception {
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
        assertFalse(mKeyStore.contains(TEST_KEYNAME));
    }

    public void testImport_Failure_BadEncoding() throws Exception {
@@ -257,12 +400,15 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {

        assertFalse("Invalid DER-encoded key should not be imported",
                mKeyStore.importKey(TEST_KEYNAME, TEST_DATA));
        assertFalse(mKeyStore.contains(TEST_KEYNAME));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    }

    public void testSign_Success() throws Exception {
        mKeyStore.password(TEST_PASSWD);

        assertTrue(mKeyStore.generate(TEST_KEYNAME));
        assertTrue(mKeyStore.contains(TEST_KEYNAME));
        final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);

        assertNotNull("Signature should not be null", signature);
@@ -272,6 +418,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
        mKeyStore.password(TEST_PASSWD);

        assertTrue(mKeyStore.generate(TEST_KEYNAME));
        assertTrue(mKeyStore.contains(TEST_KEYNAME));
        final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);

        assertNotNull("Signature should not be null", signature);
@@ -406,6 +553,38 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
                mKeyStore.ungrant(TEST_KEYNAME, 0));
    }

    public void testMigrate_grantedUid_Wifi_Success() throws Exception {
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertFalse(mKeyStore.contains(TEST_KEYNAME));

        assertTrue(mKeyStore.generate(TEST_KEYNAME));

        assertTrue(mKeyStore.contains(TEST_KEYNAME));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));

        assertTrue(mKeyStore.migrate(TEST_KEYNAME, Process.WIFI_UID));

        assertFalse(mKeyStore.contains(TEST_KEYNAME));
        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    }

    public void testMigrate_ungrantedUid_Bluetooth_Failure() throws Exception {
        assertTrue(mKeyStore.password(TEST_PASSWD));

        assertFalse(mKeyStore.contains(TEST_KEYNAME));

        assertTrue(mKeyStore.generate(TEST_KEYNAME));

        assertTrue(mKeyStore.contains(TEST_KEYNAME));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));

        assertFalse(mKeyStore.migrate(TEST_KEYNAME, Process.BLUETOOTH_UID));

        assertTrue(mKeyStore.contains(TEST_KEYNAME));
        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
    }

    /**
     * The amount of time to allow before and after expected time for variance
     * in timing tests.