DO NOT MERGE Support cross-UID access from AndroidKeyStore.

This is meant for exposing the pre-existing cross-UID access to keys
backed by the keystore service via higher-level JCA API. For example,
this lets system_server use Wi-Fi or VPN UID keys via JCA API.

To obtain a JCA AndroidKeyStore KeyStore for another UID, use the
hidden system API AndroidKeyStoreProvider.getKeyStoreForUid(uid).

To generate a key owned by another UID, invoke setUid(uid) on
KeyGenParameterSpec.Builder.

This CL does not change the security policy, such as which UID can
access/modify which UIDs' keys. The policy is that only certain system
UIDs are permitted to access keys of certain other system UIDs.

Cherry-picked from 3876b1be27e3aefde9a72eb2e4f856e94fc5f946
Bug: 23978113
Change-Id: Ie381530f41dc41c50d52f675fb9e68bc87c006de
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 5d777b0..c8333c8 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -217,13 +217,22 @@
      * Returns {@code true} if there was at least one of those types.
      */
     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
+        return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete all types (private key, certificate, CA certificate) for a
+     * particular {@code alias}. All three can exist for any given alias.
+     * Returns {@code true} if there was at least one of those types.
+     */
+    public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
          * Make sure every type is deleted. There can be all three types, so
          * don't use a conditional here.
          */
-        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias)
-                | keystore.delete(Credentials.USER_SECRET_KEY + alias)
-                | deleteCertificateTypesForAlias(keystore, alias);
+        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid)
+                | keystore.delete(Credentials.USER_SECRET_KEY + alias, uid)
+                | deleteCertificateTypesForAlias(keystore, alias, uid);
     }
 
     /**
@@ -232,12 +241,21 @@
      * Returns {@code true} if there was at least one of those types.
      */
     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
+        return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete all types (private key, certificate, CA certificate) for a
+     * particular {@code alias}. All three can exist for any given alias.
+     * Returns {@code true} if there was at least one of those types.
+     */
+    public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
          * Make sure every certificate type is deleted. There can be two types,
          * so don't use a conditional here.
          */
-        return keystore.delete(Credentials.USER_CERTIFICATE + alias)
-                | keystore.delete(Credentials.CA_CERTIFICATE + alias);
+        return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
+                | keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
     }
 
     /**
@@ -245,7 +263,15 @@
      * Returns {@code true} if an entry was was deleted.
      */
     static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias) {
-        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias);
+        return deletePrivateKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete private key for a particular {@code alias}.
+     * Returns {@code true} if an entry was was deleted.
+     */
+    static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
+        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid);
     }
 
     /**
@@ -253,6 +279,14 @@
      * Returns {@code true} if an entry was was deleted.
      */
     public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias) {
-        return keystore.delete(Credentials.USER_SECRET_KEY + alias);
+        return deleteSecretKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete secret key for a particular {@code alias}.
+     * Returns {@code true} if an entry was was deleted.
+     */
+    public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
+        return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
     }
 }
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 7de26d6..5b2594d 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -374,7 +374,7 @@
                 throw new KeyChainException("keystore had a problem");
             }
             return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
-                    KeyStore.getInstance(), keyId);
+                    KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
         } catch (RemoteException e) {
             throw new KeyChainException(e);
         } catch (RuntimeException e) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 98b44dc..d7a0a9a 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -640,7 +640,7 @@
      * {@link KeyStoreException}.
      */
     public InvalidKeyException getInvalidKeyException(
-            String keystoreKeyAlias, KeyStoreException e) {
+            String keystoreKeyAlias, int uid, KeyStoreException e) {
         switch (e.getErrorCode()) {
             case LOCKED:
                 return new UserNotAuthenticatedException();
@@ -658,7 +658,8 @@
                 // to authenticate.
                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
                 int getKeyCharacteristicsErrorCode =
-                        getKeyCharacteristics(keystoreKeyAlias, null, null, keyCharacteristics);
+                        getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
+                                keyCharacteristics);
                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
                     return new InvalidKeyException(
                             "Failed to obtained key characteristics",
@@ -708,7 +709,8 @@
      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
      * code.
      */
-    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int errorCode) {
-        return getInvalidKeyException(keystoreKeyAlias, getKeyStoreException(errorCode));
+    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
+            int errorCode) {
+        return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index 38cacd0..042dc83 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -249,7 +249,8 @@
                 purpose,
                 true, // permit aborting this operation if keystore runs out of resources
                 keymasterInputArgs,
-                additionalEntropy);
+                additionalEntropy,
+                mKey.getUid());
         if (opResult == null) {
             throw new KeyStoreConnectException();
         }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
index 10aab7e..45f2110 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
@@ -155,9 +155,9 @@
 
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = getKeyStore().getKeyCharacteristics(
-                key.getAlias(), null, null, keyCharacteristics);
+                key.getAlias(), null, null, key.getUid(), keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
-            throw getKeyStore().getInvalidKeyException(key.getAlias(), errorCode);
+            throw getKeyStore().getInvalidKeyException(key.getAlias(), key.getUid(), errorCode);
         }
         long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
         if (keySizeBits == -1) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
index 5dbcd68..aa7bdff 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
@@ -28,8 +28,8 @@
 public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
     private final ECParameterSpec mParams;
 
-    public AndroidKeyStoreECPrivateKey(String alias, ECParameterSpec params) {
-        super(alias, KeyProperties.KEY_ALGORITHM_EC);
+    public AndroidKeyStoreECPrivateKey(String alias, int uid, ECParameterSpec params) {
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC);
         mParams = params;
     }
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
index 3ed396d..2efaeb6 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
@@ -30,15 +30,15 @@
     private final ECParameterSpec mParams;
     private final ECPoint mW;
 
-    public AndroidKeyStoreECPublicKey(String alias, byte[] x509EncodedForm, ECParameterSpec params,
+    public AndroidKeyStoreECPublicKey(String alias, int uid, byte[] x509EncodedForm, ECParameterSpec params,
             ECPoint w) {
-        super(alias, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
         mParams = params;
         mW = w;
     }
 
-    public AndroidKeyStoreECPublicKey(String alias, ECPublicKey info) {
-        this(alias, info.getEncoded(), info.getParams(), info.getW());
+    public AndroidKeyStoreECPublicKey(String alias, int uid, ECPublicKey info) {
+        this(alias, uid, info.getEncoded(), info.getParams(), info.getW());
         if (!"X.509".equalsIgnoreCase(info.getFormat())) {
             throw new IllegalArgumentException(
                     "Unsupported key export format: " + info.getFormat());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
index d20e3af..2e8ac32 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
@@ -168,7 +168,8 @@
                 KeymasterDefs.KM_PURPOSE_SIGN,
                 true,
                 keymasterArgs,
-                null); // no additional entropy needed for HMAC because it's deterministic
+                null, // no additional entropy needed for HMAC because it's deterministic
+                mKey.getUid());
 
         if (opResult == null) {
             throw new KeyStoreConnectException();
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
index e76802f..e8e6310 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
@@ -25,10 +25,12 @@
  */
 public class AndroidKeyStoreKey implements Key {
     private final String mAlias;
+    private final int mUid;
     private final String mAlgorithm;
 
-    public AndroidKeyStoreKey(String alias, String algorithm) {
+    public AndroidKeyStoreKey(String alias, int uid, String algorithm) {
         mAlias = alias;
+        mUid = uid;
         mAlgorithm = algorithm;
     }
 
@@ -36,6 +38,10 @@
         return mAlias;
     }
 
+    int getUid() {
+        return mUid;
+    }
+
     @Override
     public String getAlgorithm() {
         return mAlgorithm;
@@ -59,6 +65,7 @@
         int result = 1;
         result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
         result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
+        result = prime * result + mUid;
         return result;
     }
 
@@ -88,6 +95,9 @@
         } else if (!mAlias.equals(other.mAlias)) {
             return false;
         }
+        if (mUid != other.mUid) {
+            return false;
+        }
         return true;
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
index 5ce4fd2..303b0f2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
@@ -62,7 +62,8 @@
                         "Unsupported key type: " + key.getClass().getName()
                         + ". KeyInfo can be obtained only for Android Keystore private keys");
             }
-            String keyAliasInKeystore = ((AndroidKeyStorePrivateKey) key).getAlias();
+            AndroidKeyStorePrivateKey keystorePrivateKey = (AndroidKeyStorePrivateKey) key;
+            String keyAliasInKeystore = keystorePrivateKey.getAlias();
             String entryAlias;
             if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
                 entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
@@ -71,7 +72,7 @@
             }
             @SuppressWarnings("unchecked")
             T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(
-                    mKeyStore, entryAlias, keyAliasInKeystore);
+                    mKeyStore, entryAlias, keyAliasInKeystore, keystorePrivateKey.getUid());
             return result;
         } else if (X509EncodedKeySpec.class.equals(keySpecClass)) {
             if (!(key instanceof AndroidKeyStorePublicKey)) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 4c174f1..e6276a4 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -297,11 +297,12 @@
         KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
         boolean success = false;
         try {
-            Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias());
+            Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias(), spec.getUid());
             int errorCode = mKeyStore.generateKey(
                     keyAliasInKeystore,
                     args,
                     additionalEntropy,
+                    spec.getUid(),
                     flags,
                     resultingKeyCharacteristics);
             if (errorCode != KeyStore.NO_ERROR) {
@@ -315,12 +316,14 @@
             } catch (IllegalArgumentException e) {
                 throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
             }
-            SecretKey result = new AndroidKeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
+            SecretKey result = new AndroidKeyStoreSecretKey(
+                    keyAliasInKeystore, spec.getUid(), keyAlgorithmJCA);
             success = true;
             return result;
         } finally {
             if (!success) {
-                Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias());
+                Credentials.deleteAllTypesForAlias(
+                        mKeyStore, spec.getKeystoreAlias(), spec.getUid());
             }
         }
     }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 79095f4..65460b5 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -147,6 +147,7 @@
     private KeyGenParameterSpec mSpec;
 
     private String mEntryAlias;
+    private int mEntryUid;
     private boolean mEncryptionAtRestRequired;
     private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
     private int mKeymasterAlgorithm = -1;
@@ -283,6 +284,7 @@
             }
 
             mEntryAlias = spec.getKeystoreAlias();
+            mEntryUid = spec.getUid();
             mSpec = spec;
             mKeymasterAlgorithm = keymasterAlgorithm;
             mEncryptionAtRestRequired = encryptionAtRestRequired;
@@ -352,6 +354,7 @@
 
     private void resetAll() {
         mEntryAlias = null;
+        mEntryUid = KeyStore.UID_SELF;
         mJcaKeyAlgorithm = null;
         mKeymasterAlgorithm = -1;
         mKeymasterPurposes = null;
@@ -470,12 +473,13 @@
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
         boolean success = false;
         try {
-            Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias);
+            Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
             KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
             int errorCode = mKeyStore.generateKey(
                     privateKeyAlias,
                     args,
                     additionalEntropy,
+                    mEntryUid,
                     flags,
                     resultingKeyCharacteristics);
             if (errorCode != KeyStore.NO_ERROR) {
@@ -486,7 +490,7 @@
             KeyPair result;
             try {
                 result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
-                        mKeyStore, privateKeyAlias);
+                        mKeyStore, privateKeyAlias, mEntryUid);
             } catch (UnrecoverableKeyException e) {
                 throw new ProviderException("Failed to load generated key pair from keystore", e);
             }
@@ -515,7 +519,7 @@
             int insertErrorCode = mKeyStore.insert(
                     Credentials.USER_CERTIFICATE + mEntryAlias,
                     certBytes,
-                    KeyStore.UID_SELF,
+                    mEntryUid,
                     flags);
             if (insertErrorCode != KeyStore.NO_ERROR) {
                 throw new ProviderException("Failed to store self-signed certificate",
@@ -526,7 +530,7 @@
             return result;
         } finally {
             if (!success) {
-                Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias);
+                Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
             }
         }
     }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
new file mode 100644
index 0000000..45d579e
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.security.KeyStore;
+import java.security.KeyStore.ProtectionParameter;
+
+class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter {
+
+    private final int mUid;
+
+    AndroidKeyStoreLoadStoreParameter(int uid) {
+        mUid = uid;
+    }
+
+    @Override
+    public ProtectionParameter getProtectionParameter() {
+        return null;
+    }
+
+    int getUid() {
+        return mUid;
+    }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
index b586ad4..06e4c88 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
@@ -25,7 +25,7 @@
  */
 public class AndroidKeyStorePrivateKey extends AndroidKeyStoreKey implements PrivateKey {
 
-    public AndroidKeyStorePrivateKey(String alias, String algorithm) {
-        super(alias, algorithm);
+    public AndroidKeyStorePrivateKey(String alias, int uid, String algorithm) {
+        super(alias, uid, algorithm);
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 85cb4df..8c20ddc 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -22,15 +22,19 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterDefs;
 
+import java.io.IOException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
+import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
 import java.security.Provider;
 import java.security.ProviderException;
 import java.security.PublicKey;
 import java.security.Security;
 import java.security.Signature;
 import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
 import java.security.interfaces.ECKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAKey;
@@ -168,6 +172,7 @@
     @NonNull
     public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
             @NonNull String alias,
+            int uid,
             @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
             @NonNull byte[] x509EncodedForm) {
         PublicKey publicKey;
@@ -181,9 +186,9 @@
             throw new ProviderException("Invalid X.509 encoding of public key", e);
         }
         if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreECPublicKey(alias, (ECPublicKey) publicKey);
+            return new AndroidKeyStoreECPublicKey(alias, uid, (ECPublicKey) publicKey);
         } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreRSAPublicKey(alias, (RSAPublicKey) publicKey);
+            return new AndroidKeyStoreRSAPublicKey(alias, uid, (RSAPublicKey) publicKey);
         } else {
             throw new ProviderException("Unsupported Android Keystore public key algorithm: "
                     + keyAlgorithm);
@@ -196,10 +201,10 @@
         String keyAlgorithm = publicKey.getAlgorithm();
         if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
             return new AndroidKeyStoreECPrivateKey(
-                    publicKey.getAlias(), ((ECKey) publicKey).getParams());
+                    publicKey.getAlias(), publicKey.getUid(), ((ECKey) publicKey).getParams());
         } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
             return new AndroidKeyStoreRSAPrivateKey(
-                    publicKey.getAlias(), ((RSAKey) publicKey).getModulus());
+                    publicKey.getAlias(), publicKey.getUid(), ((RSAKey) publicKey).getModulus());
         } else {
             throw new ProviderException("Unsupported Android Keystore public key algorithm: "
                     + keyAlgorithm);
@@ -208,18 +213,18 @@
 
     @NonNull
     public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
             throws UnrecoverableKeyException {
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = keyStore.getKeyCharacteristics(
-                privateKeyAlias, null, null, keyCharacteristics);
+                privateKeyAlias, null, null, uid, keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain information about private key")
                     .initCause(KeyStore.getKeyStoreException(errorCode));
         }
         ExportResult exportResult = keyStore.exportKey(
-                privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+                privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null, uid);
         if (exportResult.resultCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
@@ -243,15 +248,15 @@
         }
 
         return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
-                privateKeyAlias, jcaKeyAlgorithm, x509EncodedPublicKey);
+                privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
     }
 
     @NonNull
     public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
             throws UnrecoverableKeyException {
         AndroidKeyStorePublicKey publicKey =
-                loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias);
+                loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid);
         AndroidKeyStorePrivateKey privateKey =
                 AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
         return new KeyPair(publicKey, privateKey);
@@ -259,19 +264,19 @@
 
     @NonNull
     public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
             throws UnrecoverableKeyException {
-        KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias);
+        KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid);
         return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
     }
 
     @NonNull
     public static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String secretKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String secretKeyAlias, int uid)
             throws UnrecoverableKeyException {
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = keyStore.getKeyCharacteristics(
-                secretKeyAlias, null, null, keyCharacteristics);
+                secretKeyAlias, null, null, uid, keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain information about key")
@@ -302,6 +307,29 @@
                     new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
         }
 
-        return new AndroidKeyStoreSecretKey(secretKeyAlias, keyAlgorithmString);
+        return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
+    }
+
+    /**
+     * Returns an {@code AndroidKeyStore} {@link java.security.KeyStore}} of the specified UID.
+     * The {@code KeyStore} contains keys and certificates owned by that UID. Such cross-UID
+     * access is permitted to a few system UIDs and only to a few other UIDs (e.g., Wi-Fi, VPN)
+     * all of which are system.
+     *
+     * <p>Note: the returned {@code KeyStore} is already initialized/loaded. Thus, there is
+     * no need to invoke {@code load} on it.
+     */
+    @NonNull
+    public static java.security.KeyStore getKeyStoreForUid(int uid)
+            throws KeyStoreException, NoSuchProviderException {
+        java.security.KeyStore result =
+                java.security.KeyStore.getInstance("AndroidKeyStore", PROVIDER_NAME);
+        try {
+            result.load(new AndroidKeyStoreLoadStoreParameter(uid));
+        } catch (NoSuchAlgorithmException | CertificateException | IOException e) {
+            throw new KeyStoreException(
+                    "Failed to load AndroidKeyStore KeyStore for UID " + uid, e);
+        }
+        return result;
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
index 9fea30d..4194780 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
@@ -28,8 +28,8 @@
 
     private final byte[] mEncoded;
 
-    public AndroidKeyStorePublicKey(String alias, String algorithm, byte[] x509EncodedForm) {
-        super(alias, algorithm);
+    public AndroidKeyStorePublicKey(String alias, int uid, String algorithm, byte[] x509EncodedForm) {
+        super(alias, uid, algorithm);
         mEncoded = ArrayUtils.cloneIfNotEmpty(x509EncodedForm);
     }
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index 56cc44c..2ae68fa 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -415,9 +415,10 @@
 
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = getKeyStore().getKeyCharacteristics(
-                keystoreKey.getAlias(), null, null, keyCharacteristics);
+                keystoreKey.getAlias(), null, null, keystoreKey.getUid(), keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
-            throw getKeyStore().getInvalidKeyException(keystoreKey.getAlias(), errorCode);
+            throw getKeyStore().getInvalidKeyException(
+                    keystoreKey.getAlias(), keystoreKey.getUid(), errorCode);
         }
         long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
         if (keySizeBits == -1) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
index 179ffd8..adb3922 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
@@ -29,8 +29,8 @@
 
     private final BigInteger mModulus;
 
-    public AndroidKeyStoreRSAPrivateKey(String alias, BigInteger modulus) {
-        super(alias, KeyProperties.KEY_ALGORITHM_RSA);
+    public AndroidKeyStoreRSAPrivateKey(String alias, int uid, BigInteger modulus) {
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA);
         mModulus = modulus;
     }
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
index 08a173e..d85aace 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
@@ -28,15 +28,15 @@
     private final BigInteger mModulus;
     private final BigInteger mPublicExponent;
 
-    public AndroidKeyStoreRSAPublicKey(String alias, byte[] x509EncodedForm, BigInteger modulus,
+    public AndroidKeyStoreRSAPublicKey(String alias, int uid, byte[] x509EncodedForm, BigInteger modulus,
             BigInteger publicExponent) {
-        super(alias, KeyProperties.KEY_ALGORITHM_RSA, x509EncodedForm);
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA, x509EncodedForm);
         mModulus = modulus;
         mPublicExponent = publicExponent;
     }
 
-    public AndroidKeyStoreRSAPublicKey(String alias, RSAPublicKey info) {
-        this(alias, info.getEncoded(), info.getModulus(), info.getPublicExponent());
+    public AndroidKeyStoreRSAPublicKey(String alias, int uid, RSAPublicKey info) {
+        this(alias, uid, info.getEncoded(), info.getModulus(), info.getPublicExponent());
         if (!"X.509".equalsIgnoreCase(info.getFormat())) {
             throw new IllegalArgumentException(
                     "Unsupported key export format: " + info.getFormat());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
index af354ab..b8e6af7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
@@ -25,7 +25,7 @@
  */
 public class AndroidKeyStoreSecretKey extends AndroidKeyStoreKey implements SecretKey {
 
-    public AndroidKeyStoreSecretKey(String alias, String algorithm) {
-        super(alias, algorithm);
+    public AndroidKeyStoreSecretKey(String alias, int uid, String algorithm) {
+        super(alias, uid, algorithm);
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 11c22a9..8d606bf 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -59,7 +59,8 @@
         if (!KeyInfo.class.equals(keySpecClass)) {
             throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
         }
-        String keyAliasInKeystore = ((AndroidKeyStoreKey) key).getAlias();
+        AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key;
+        String keyAliasInKeystore = keystoreKey.getAlias();
         String entryAlias;
         if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
             entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
@@ -67,13 +68,14 @@
             throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
         }
 
-        return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore);
+        return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid());
     }
 
-    static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore) {
+    static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore,
+            int keyUid) {
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-        int errorCode =
-                keyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
+        int errorCode = keyStore.getKeyCharacteristics(
+                keyAliasInKeystore, null, null, keyUid, keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
             throw new ProviderException("Failed to obtain information about key."
                     + " Keystore error: " + errorCode);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
index 76240dd..da47b6b 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -204,8 +204,8 @@
                 mSigning ? KeymasterDefs.KM_PURPOSE_SIGN : KeymasterDefs.KM_PURPOSE_VERIFY,
                 true, // permit aborting this operation if keystore runs out of resources
                 keymasterInputArgs,
-                null // no additional entropy for begin -- only finish might need some
-                );
+                null, // no additional entropy for begin -- only finish might need some
+                mKey.getUid());
         if (opResult == null) {
             throw new KeyStoreConnectException();
         }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index d300a92..cdcc7a2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -17,7 +17,6 @@
 package android.security.keystore;
 
 import libcore.util.EmptyArray;
-
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.security.KeyStoreParameter;
@@ -34,6 +33,7 @@
 import java.io.OutputStream;
 import java.security.Key;
 import java.security.KeyStore.Entry;
+import java.security.KeyStore.LoadStoreParameter;
 import java.security.KeyStore.PrivateKeyEntry;
 import java.security.KeyStore.ProtectionParameter;
 import java.security.KeyStore.SecretKeyEntry;
@@ -84,6 +84,7 @@
     public static final String NAME = "AndroidKeyStore";
 
     private KeyStore mKeyStore;
+    private int mUid = KeyStore.UID_SELF;
 
     @Override
     public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
@@ -91,11 +92,11 @@
         if (isPrivateKeyEntry(alias)) {
             String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
             return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
-                    mKeyStore, privateKeyAlias);
+                    mKeyStore, privateKeyAlias, mUid);
         } else if (isSecretKeyEntry(alias)) {
             String secretKeyAlias = Credentials.USER_SECRET_KEY + alias;
             return AndroidKeyStoreProvider.loadAndroidKeyStoreSecretKeyFromKeystore(
-                    mKeyStore, secretKeyAlias);
+                    mKeyStore, secretKeyAlias, mUid);
         } else {
             // Key not found
             return null;
@@ -115,7 +116,7 @@
 
         final Certificate[] caList;
 
-        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
         if (caBytes != null) {
             final Collection<X509Certificate> caChain = toCertificates(caBytes);
 
@@ -141,12 +142,12 @@
             throw new NullPointerException("alias == null");
         }
 
-        byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+        byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
         if (encodedCert != null) {
             return getCertificateForPrivateKeyEntry(alias, encodedCert);
         }
 
-        encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
         if (encodedCert != null) {
             return getCertificateForTrustedCertificateEntry(encodedCert);
         }
@@ -183,13 +184,13 @@
         }
 
         String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
-        if (mKeyStore.contains(privateKeyAlias)) {
+        if (mKeyStore.contains(privateKeyAlias, mUid)) {
             // As expected, keystore contains the private key corresponding to this public key. Wrap
             // the certificate so that its getPublicKey method returns an Android Keystore
             // PublicKey. This key will delegate crypto operations involving this public key to
             // Android Keystore when higher-priority providers do not offer these crypto
             // operations for this key.
-            return wrapIntoKeyStoreCertificate(privateKeyAlias, cert);
+            return wrapIntoKeyStoreCertificate(privateKeyAlias, mUid, cert);
         } else {
             // This KeyStore entry/alias is supposed to contain the private key corresponding to
             // the public key in this certificate, but it does not for some reason. It's probably a
@@ -206,9 +207,9 @@
      * find out which key alias to use. These operations cannot work without an alias.
      */
     private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
-            String privateKeyAlias, X509Certificate certificate) {
+            String privateKeyAlias, int uid, X509Certificate certificate) {
         return (certificate != null)
-                ? new KeyStoreX509Certificate(privateKeyAlias, certificate) : null;
+                ? new KeyStoreX509Certificate(privateKeyAlias, uid, certificate) : null;
     }
 
     private static X509Certificate toCertificate(byte[] bytes) {
@@ -235,7 +236,7 @@
     }
 
     private Date getModificationDate(String alias) {
-        final long epochMillis = mKeyStore.getmtime(alias);
+        final long epochMillis = mKeyStore.getmtime(alias, mUid);
         if (epochMillis == -1L) {
             return null;
         }
@@ -516,13 +517,14 @@
             if (shouldReplacePrivateKey) {
                 // Delete the stored private key and any related entries before importing the
                 // provided key
-                Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+                Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
                 KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
                 int errorCode = mKeyStore.importKey(
                         Credentials.USER_PRIVATE_KEY + alias,
                         importArgs,
                         KeymasterDefs.KM_KEY_FORMAT_PKCS8,
                         pkcs8EncodedPrivateKeyBytes,
+                        mUid,
                         flags,
                         resultingKeyCharacteristics);
                 if (errorCode != KeyStore.NO_ERROR) {
@@ -531,13 +533,13 @@
                 }
             } else {
                 // Keep the stored private key around -- delete all other entry types
-                Credentials.deleteCertificateTypesForAlias(mKeyStore, alias);
-                Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias);
+                Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
+                Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
             }
 
             // Store the leaf certificate
             int errorCode = mKeyStore.insert(Credentials.USER_CERTIFICATE + alias, userCertBytes,
-                    KeyStore.UID_SELF, flags);
+                    mUid, flags);
             if (errorCode != KeyStore.NO_ERROR) {
                 throw new KeyStoreException("Failed to store certificate #0",
                         KeyStore.getKeyStoreException(errorCode));
@@ -545,7 +547,7 @@
 
             // Store the certificate chain
             errorCode = mKeyStore.insert(Credentials.CA_CERTIFICATE + alias, chainBytes,
-                    KeyStore.UID_SELF, flags);
+                    mUid, flags);
             if (errorCode != KeyStore.NO_ERROR) {
                 throw new KeyStoreException("Failed to store certificate chain",
                         KeyStore.getKeyStoreException(errorCode));
@@ -554,10 +556,10 @@
         } finally {
             if (!success) {
                 if (shouldReplacePrivateKey) {
-                    Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+                    Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
                 } else {
-                    Credentials.deleteCertificateTypesForAlias(mKeyStore, alias);
-                    Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias);
+                    Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
+                    Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
                 }
             }
         }
@@ -712,13 +714,14 @@
             throw new KeyStoreException(e);
         }
 
-        Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias);
+        Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
         String keyAliasInKeystore = Credentials.USER_SECRET_KEY + entryAlias;
         int errorCode = mKeyStore.importKey(
                 keyAliasInKeystore,
                 args,
                 KeymasterDefs.KM_KEY_FORMAT_RAW,
                 keyMaterial,
+                mUid,
                 0, // flags
                 new KeyCharacteristics());
         if (errorCode != KeyStore.NO_ERROR) {
@@ -751,8 +754,7 @@
             throw new KeyStoreException(e);
         }
 
-        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE)) {
+        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded, mUid, KeyStore.FLAG_NONE)) {
             throw new KeyStoreException("Couldn't insert certificate; is KeyStore initialized?");
         }
     }
@@ -764,13 +766,13 @@
         }
         // At least one entry corresponding to this alias exists in keystore
 
-        if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
+        if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid)) {
             throw new KeyStoreException("Failed to delete entry: " + alias);
         }
     }
 
     private Set<String> getUniqueAliases() {
-        final String[] rawAliases = mKeyStore.list("");
+        final String[] rawAliases = mKeyStore.list("", mUid);
         if (rawAliases == null) {
             return new HashSet<String>();
         }
@@ -800,10 +802,10 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias)
-                || mKeyStore.contains(Credentials.USER_SECRET_KEY + alias)
-                || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias)
-                || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias);
+        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid)
+                || mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid)
+                || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias, mUid)
+                || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
     }
 
     @Override
@@ -825,7 +827,7 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias);
+        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid);
     }
 
     private boolean isSecretKeyEntry(String alias) {
@@ -833,7 +835,7 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.USER_SECRET_KEY + alias);
+        return mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid);
     }
 
     private boolean isCertificateEntry(String alias) {
@@ -841,7 +843,7 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.CA_CERTIFICATE + alias);
+        return mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
     }
 
     @Override
@@ -876,10 +878,10 @@
          * equivalent to the USER_CERTIFICATE prefix for the Android keystore
          * convention.
          */
-        final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE);
+        final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE, mUid);
         if (certAliases != null) {
             for (String alias : certAliases) {
-                final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+                final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
                 if (certBytes == null) {
                     continue;
                 }
@@ -896,14 +898,14 @@
          * Look at all the TrustedCertificateEntry types. Skip all the
          * PrivateKeyEntry we looked at above.
          */
-        final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE);
+        final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE, mUid);
         if (certAliases != null) {
             for (String alias : caAliases) {
                 if (nonCaEntries.contains(alias)) {
                     continue;
                 }
 
-                final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+                final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
                 if (certBytes == null) {
                     continue;
                 }
@@ -936,6 +938,23 @@
 
         // Unfortunate name collision.
         mKeyStore = KeyStore.getInstance();
+        mUid = KeyStore.UID_SELF;
+    }
+
+    @Override
+    public void engineLoad(LoadStoreParameter param) throws IOException,
+            NoSuchAlgorithmException, CertificateException {
+        int uid = KeyStore.UID_SELF;
+        if (param != null) {
+            if (param instanceof AndroidKeyStoreLoadStoreParameter) {
+                uid = ((AndroidKeyStoreLoadStoreParameter) param).getUid();
+            } else {
+                throw new IllegalArgumentException(
+                        "Unsupported param type: " + param.getClass());
+            }
+        }
+        mKeyStore = KeyStore.getInstance();
+        mUid = uid;
     }
 
     @Override
@@ -945,7 +964,7 @@
             throw new KeyStoreException("entry == null");
         }
 
-        Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+        Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
 
         if (entry instanceof java.security.KeyStore.TrustedCertificateEntry) {
             java.security.KeyStore.TrustedCertificateEntry trE =
@@ -976,16 +995,20 @@
      */
     static class KeyStoreX509Certificate extends DelegatingX509Certificate {
         private final String mPrivateKeyAlias;
-        KeyStoreX509Certificate(String privateKeyAlias, X509Certificate delegate) {
+        private final int mPrivateKeyUid;
+        KeyStoreX509Certificate(String privateKeyAlias, int privateKeyUid,
+                X509Certificate delegate) {
             super(delegate);
             mPrivateKeyAlias = privateKeyAlias;
+            mPrivateKeyUid = privateKeyUid;
         }
 
         @Override
         public PublicKey getPublicKey() {
             PublicKey original = super.getPublicKey();
             return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
-                    mPrivateKeyAlias, original.getAlgorithm(), original.getEncoded());
+                    mPrivateKeyAlias, mPrivateKeyUid,
+                    original.getAlgorithm(), original.getEncoded());
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index f42d750..add199f 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.app.KeyguardManager;
 import android.hardware.fingerprint.FingerprintManager;
+import android.security.KeyStore;
 import android.text.TextUtils;
 
 import java.math.BigInteger;
@@ -231,6 +232,7 @@
     private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
 
     private final String mKeystoreAlias;
+    private final int mUid;
     private final int mKeySize;
     private final AlgorithmParameterSpec mSpec;
     private final X500Principal mCertificateSubject;
@@ -254,6 +256,7 @@
      */
     public KeyGenParameterSpec(
             String keyStoreAlias,
+            int uid,
             int keySize,
             AlgorithmParameterSpec spec,
             X500Principal certificateSubject,
@@ -293,6 +296,7 @@
         }
 
         mKeystoreAlias = keyStoreAlias;
+        mUid = uid;
         mKeySize = keySize;
         mSpec = spec;
         mCertificateSubject = certificateSubject;
@@ -323,6 +327,16 @@
     }
 
     /**
+     * Returns the UID which will own the key. {@code -1} is an alias for the UID of the current
+     * process.
+     *
+     * @hide
+     */
+    public int getUid() {
+        return mUid;
+    }
+
+    /**
      * Returns the requested key size. If {@code -1}, the size should be looked up from
      * {@link #getAlgorithmParameterSpec()}, if provided, otherwise an algorithm-specific default
      * size should be used.
@@ -531,6 +545,7 @@
         private final String mKeystoreAlias;
         private @KeyProperties.PurposeEnum int mPurposes;
 
+        private int mUid = KeyStore.UID_SELF;
         private int mKeySize = -1;
         private AlgorithmParameterSpec mSpec;
         private X500Principal mCertificateSubject;
@@ -575,6 +590,19 @@
         }
 
         /**
+         * Sets the UID which will own the key.
+         *
+         * @param uid UID or {@code -1} for the UID of the current process.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setUid(int uid) {
+            mUid = uid;
+            return this;
+        }
+
+        /**
          * Sets the size (in bits) of the key to be generated. For instance, for RSA keys this sets
          * the modulus size, for EC keys this selects a curve with a matching field size, and for
          * symmetric keys this sets the size of the bitstring which is their key material.
@@ -936,6 +964,7 @@
         public KeyGenParameterSpec build() {
             return new KeyGenParameterSpec(
                     mKeystoreAlias,
+                    mUid,
                     mKeySize,
                     mSpec,
                     mCertificateSubject,
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
index 27c1b2a..773729e 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
@@ -51,7 +51,7 @@
         // An error occured. However, some errors should not lead to init throwing an exception.
         // See below.
         InvalidKeyException e =
-                keyStore.getInvalidKeyException(key.getAlias(), beginOpResultCode);
+                keyStore.getInvalidKeyException(key.getAlias(), key.getUid(), beginOpResultCode);
         switch (beginOpResultCode) {
             case KeyStore.OP_AUTH_NEEDED:
                 // Operation needs to be authorized by authenticating the user. Don't throw an
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
index e5c15c5..1af0b7d 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
@@ -384,6 +384,7 @@
                 pubKey,
                 AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
                         Credentials.USER_PRIVATE_KEY + alias,
+                        KeyStore.UID_SELF,
                         x509userCert.getPublicKey().getAlgorithm(),
                         x509userCert.getPublicKey().getEncoded()));
 
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
index c3b731b..aa718dc 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
@@ -1918,7 +1918,7 @@
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
 
         KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
-                keyStore, privateKeyAlias);
+                keyStore, privateKeyAlias, KeyStore.UID_SELF);
 
         final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
         certGen.setPublicKey(keyPair.getPublic());