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());