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

Commit 78ad8491 authored by Kenny Root's avatar Kenny Root Committed by Kenny Root
Browse files

KeyStore: add API to uid versions

In previous commits, we added the ability to specify which UID we want to
target on certain operations. This commit adds the ability to reach those
binder calls from the KeyStore class.

Also fix a problem where saw() was not reading all the values returned via
the Binder call. This changes the semantics to return a null instead of
failing silently when it's not possible to search.

Change-Id: I32098dc0eb42e09ace89f6b7455766842a72e9f4
parent ebebb80b
Loading
Loading
Loading
Loading
+4 −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();
+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;
    }
+42 −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);
+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);
    }
+153 −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);