diff options
author | Alex Klyubin <klyubin@google.com> | 2015-09-09 14:55:03 -0700 |
---|---|---|
committer | Alex Klyubin <klyubin@google.com> | 2015-09-10 15:35:06 -0700 |
commit | 3876b1be27e3aefde9a72eb2e4f856e94fc5f946 (patch) | |
tree | 5783b18f074f1971a83a615ef805f5483f6cfb90 /keystore/java | |
parent | 435acfc88917e3535462ea520b01d0868266acd2 (diff) |
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.
Bug: 23978113
Change-Id: Ie381530f41dc41c50d52f675fb9e68bc87c006de
Diffstat (limited to 'keystore/java')
25 files changed, 284 insertions, 107 deletions
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java index 5d777b0cb942..c8333c87c69c 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 7de26d696538..5b2594dcc9e7 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 98b44dc43144..d7a0a9a7777c 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 38cacd0c43b4..042dc83d4aa9 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 10aab7e59ff5..45f2110e0c77 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 5dbcd681fe8f..aa7bdffb9e07 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 3ed396dedeb9..2efaeb6545a0 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 d20e3afd2672..2e8ac3236463 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 e76802f1dca5..e8e63105925f 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 5ce4fd2cde2d..303b0f2c05c2 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 4c174f13a27a..e6276a46bc3a 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 79095f42cd06..65460b5ceb29 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 000000000000..45d579e371c6 --- /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 b586ad4f921c..06e4c88fa632 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 ba39ba70f4d3..c31a8b7bf2bf 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. + * + * <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 9fea30d23a00..4194780906b7 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 56cc44cc7cc1..2ae68fa80117 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 179ffd8c1efd..adb39222e076 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 08a173e4a0b0..d85aaceb98e3 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 af354ab560ba..b8e6af7d936e 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 11c22a9f827a..8d606bf97d0c 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 76240dd06265..da47b6bde69a 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 d300a9297054..cdcc7a2db5b2 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<X509Certificate> caChain = toCertificates(caBytes); @@ -141,12 +142,12 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { * 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } } 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { // 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } // 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { * 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { * 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { // 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { 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 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { */ 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 f42d75081899..add199f139a0 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; 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 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { 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 final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ public KeyGenParameterSpec( String keyStoreAlias, + int uid, int keySize, AlgorithmParameterSpec spec, X500Principal certificateSubject, @@ -293,6 +296,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } mKeystoreAlias = keyStoreAlias; + mUid = uid; mKeySize = keySize; mSpec = spec; mCertificateSubject = certificateSubject; @@ -323,6 +327,16 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** + * 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 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { 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 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** + * 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 final class KeyGenParameterSpec implements AlgorithmParameterSpec { 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 27c1b2ac2182..773729e7e7df 100644 --- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java +++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java @@ -51,7 +51,7 @@ abstract class KeyStoreCryptoOperationUtils { // 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 |