diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java index 5d777b0cb942b..c8333c87c69cb 100644 --- a/keystore/java/android/security/Credentials.java +++ b/keystore/java/android/security/Credentials.java @@ -217,13 +217,22 @@ public class Credentials { * 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 @@ public class Credentials { * 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 @@ public class Credentials { * 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 @@ public class Credentials { * 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 7de26d6965383..5b2594dcc9e73 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -374,7 +374,7 @@ public final class KeyChain { 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 98b44dc431442..d7a0a9a7777c0 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -640,7 +640,7 @@ public class KeyStore { * {@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 @@ public class KeyStore { // 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 @@ public class KeyStore { * 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 38cacd0c43b49..042dc83d4aa93 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java @@ -249,7 +249,8 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor 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 10aab7e59ff50..45f2110e0c777 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java @@ -155,9 +155,9 @@ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignature 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 5dbcd681fe8f2..aa7bdffb9e073 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java @@ -28,8 +28,8 @@ import java.security.spec.ECParameterSpec; 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 3ed396dedeb98..2efaeb6545a0c 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java @@ -30,15 +30,15 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme 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 d20e3afd26725..2e8ac32364633 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java @@ -168,7 +168,8 @@ public abstract class AndroidKeyStoreHmacSpi extends MacSpi implements KeyStoreC 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 e76802f1dca5f..e8e63105925f4 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java @@ -25,10 +25,12 @@ import java.security.Key; */ 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 @@ public class AndroidKeyStoreKey implements Key { return mAlias; } + int getUid() { + return mUid; + } + @Override public String getAlgorithm() { return mAlgorithm; @@ -59,6 +65,7 @@ public class AndroidKeyStoreKey implements Key { 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 @@ public class AndroidKeyStoreKey implements Key { } 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 5ce4fd2cde2dc..303b0f2c05c26 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java @@ -62,7 +62,8 @@ public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi { "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 @@ public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi { } @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 4c174f13a27ac..e6276a46bc3ae 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java @@ -297,11 +297,12 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { 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 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } 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 79095f42cd064..65460b5ceb291 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -147,6 +147,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato 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 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } mEntryAlias = spec.getKeystoreAlias(); + mEntryUid = spec.getUid(); mSpec = spec; mKeymasterAlgorithm = keymasterAlgorithm; mEncryptionAtRestRequired = encryptionAtRestRequired; @@ -352,6 +354,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private void resetAll() { mEntryAlias = null; + mEntryUid = KeyStore.UID_SELF; mJcaKeyAlgorithm = null; mKeymasterAlgorithm = -1; mKeymasterPurposes = null; @@ -470,12 +473,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato 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 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato 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 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato 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 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato 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 0000000000000..45d579e371c61 --- /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 b586ad4f921c8..06e4c88fa6321 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java +++ b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java @@ -25,7 +25,7 @@ import java.security.PrivateKey; */ 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 ba39ba70f4d3b..c31a8b7bf2bf4 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.ExportResult; 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; @@ -167,6 +171,7 @@ public class AndroidKeyStoreProvider extends Provider { @NonNull public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey( @NonNull String alias, + int uid, @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm, @NonNull byte[] x509EncodedForm) { PublicKey publicKey; @@ -180,9 +185,9 @@ public class AndroidKeyStoreProvider extends Provider { 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); @@ -195,10 +200,10 @@ public class AndroidKeyStoreProvider extends Provider { 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); @@ -207,18 +212,18 @@ public class AndroidKeyStoreProvider extends Provider { @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") @@ -242,15 +247,15 @@ public class AndroidKeyStoreProvider extends Provider { } 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); @@ -258,19 +263,19 @@ public class AndroidKeyStoreProvider extends Provider { @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") @@ -301,6 +306,29 @@ public class AndroidKeyStoreProvider extends Provider { 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. + * + *
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 9fea30d23a00d..4194780906b75 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
@@ -28,8 +28,8 @@ public class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements Publ
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 56cc44cc7cc10..2ae68fa801173 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -415,9 +415,10 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
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 179ffd8c1efd9..adb39222e0767 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
@@ -29,8 +29,8 @@ public class AndroidKeyStoreRSAPrivateKey extends AndroidKeyStorePrivateKey impl
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 08a173e4a0b05..d85aaceb98e3f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
@@ -28,15 +28,15 @@ public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implem
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 af354ab560ba1..b8e6af7d936e9 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
@@ -25,7 +25,7 @@ import javax.crypto.SecretKey;
*/
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 11c22a9f827a0..8d606bf97d0c8 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -59,7 +59,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
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 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
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 76240dd06265a..da47b6bde69af 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -204,8 +204,8 @@ abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
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 d300a92970543..cdcc7a2db5b26 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.InputStream;
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 class AndroidKeyStoreSpi extends KeyStoreSpi {
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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
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