summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java2
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java333
2 files changed, 148 insertions, 187 deletions
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
index 5b6971007077..dd943d422e62 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
@@ -40,7 +40,7 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider {
// classes when this provider is instantiated and installed early on during each app's
// initialization process.
- private static final String PACKAGE_NAME = "android.security.keystore";
+ private static final String PACKAGE_NAME = "android.security.keystore2";
private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
PACKAGE_NAME + ".AndroidKeyStoreSecretKey";
private static final String KEYSTORE_PRIVATE_KEY_CLASS_NAME =
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index b759733a7573..e7fcbdb84ab3 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -17,36 +17,33 @@
package android.security.keystore2;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
+import android.security.KeyStore2;
+import android.security.KeyStoreSecurityLevel;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyStoreCryptoOperation;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyEntryResponse;
+import android.system.keystore2.KeyMetadata;
+import android.system.keystore2.ResponseCode;
-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;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
-import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -56,7 +53,6 @@ import javax.crypto.Mac;
*
* @hide
*/
-@SystemApi
public class AndroidKeyStoreProvider extends Provider {
private static final String PROVIDER_NAME = "AndroidKeyStore";
@@ -68,7 +64,7 @@ public class AndroidKeyStoreProvider extends Provider {
// Instead, they need to be offered by AndroidKeyStoreBCWorkaroundProvider. See its Javadoc
// for details.
- private static final String PACKAGE_NAME = "android.security.keystore";
+ private static final String PACKAGE_NAME = "android.security.keystore2";
private static final String DESEDE_SYSTEM_PROPERTY =
"ro.hardware.keystore_desede";
@@ -165,7 +161,6 @@ public class AndroidKeyStoreProvider extends Provider {
* @throws IllegalStateException if the provided primitive is not initialized.
* @hide
*/
- @UnsupportedAppUsage
public static long getKeyStoreOperationHandle(Object cryptoPrimitive) {
if (cryptoPrimitive == null) {
throw new NullPointerException();
@@ -191,192 +186,188 @@ public class AndroidKeyStoreProvider extends Provider {
return ((KeyStoreCryptoOperation) spi).getOperationHandle();
}
- /** @hide **/
- @NonNull
- public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
- @NonNull String alias,
- int uid,
- @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
- @NonNull byte[] x509EncodedForm) {
- PublicKey publicKey;
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
- publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedForm));
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain " + keyAlgorithm + " KeyFactory", e);
- } catch (InvalidKeySpecException e) {
- throw new ProviderException("Invalid X.509 encoding of public key", e);
- }
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreECPublicKey(alias, uid, (ECPublicKey) publicKey);
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreRSAPublicKey(alias, uid, (RSAPublicKey) publicKey);
- } else {
- throw new ProviderException("Unsupported Android Keystore public key algorithm: "
- + keyAlgorithm);
- }
- }
-
- @NonNull
- private static AndroidKeyStorePrivateKey getAndroidKeyStorePrivateKey(
- @NonNull AndroidKeyStorePublicKey publicKey) {
- String keyAlgorithm = publicKey.getAlgorithm();
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreECPrivateKey(
- publicKey.getAlias(), publicKey.getUid(), ((ECKey) publicKey).getParams());
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreRSAPrivateKey(
- publicKey.getAlias(), publicKey.getUid(), ((RSAKey) publicKey).getModulus());
- } else {
- throw new ProviderException("Unsupported Android Keystore public key algorithm: "
- + keyAlgorithm);
- }
- }
-
- @NonNull
- private static KeyCharacteristics getKeyCharacteristics(@NonNull KeyStore keyStore,
- @NonNull String alias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = keyStore.getKeyCharacteristics(
- alias, null, null, uid, keyCharacteristics);
- if (errorCode == KeyStore.KEY_PERMANENTLY_INVALIDATED) {
- throw (KeyPermanentlyInvalidatedException)
- new KeyPermanentlyInvalidatedException(
- "User changed or deleted their auth credentials",
- KeyStore.getKeyStoreException(errorCode));
- }
- if (errorCode != KeyStore.NO_ERROR) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to obtain information about key")
- .initCause(KeyStore.getKeyStoreException(errorCode));
- }
- return keyCharacteristics;
- }
-
+ /**
+ * This helper function gets called if the key loaded from the keystore daemon
+ * is for an asymmetric algorithm. It constructs an instance of {@link AndroidKeyStorePublicKey}
+ * which implements {@link PublicKey}.
+ *
+ * @param descriptor The original key descriptor that was used to load the key.
+ *
+ * @param metadata The key metadata which includes the public key material, a reference to the
+ * stored private key material, the key characteristics.
+ * @param iSecurityLevel A binder interface that allows using the private key.
+ * @param algorithm Must indicate EC or RSA.
+ * @return AndroidKeyStorePublicKey
+ * @throws UnrecoverableKeyException
+ * @hide
+ */
@NonNull
- private static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- KeyCharacteristics keyCharacteristics)
+ static AndroidKeyStorePublicKey makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
+ @NonNull KeyDescriptor descriptor,
+ @NonNull KeyMetadata metadata,
+ @NonNull KeyStoreSecurityLevel iSecurityLevel, int algorithm)
throws UnrecoverableKeyException {
- ExportResult exportResult = keyStore.exportKey(
- 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")
- .initCause(KeyStore.getKeyStoreException(exportResult.resultCode));
- }
- final byte[] x509EncodedPublicKey = exportResult.exportData;
-
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
+ if (metadata.certificate == null) {
+ throw new UnrecoverableKeyException("Failed to obtain X.509 form of public key."
+ + " Keystore has no public certificate stored.");
}
+ final byte[] x509EncodedPublicKey = metadata.certificate;
String jcaKeyAlgorithm;
try {
jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
- keymasterAlgorithm);
+ algorithm);
} catch (IllegalArgumentException e) {
throw (UnrecoverableKeyException)
new UnrecoverableKeyException("Failed to load private key")
- .initCause(e);
+ .initCause(e);
+ }
+
+ PublicKey publicKey;
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance(jcaKeyAlgorithm);
+ publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedPublicKey));
+ } catch (NoSuchAlgorithmException e) {
+ throw new ProviderException(
+ "Failed to obtain " + jcaKeyAlgorithm + " KeyFactory", e);
+ } catch (InvalidKeySpecException e) {
+ throw new ProviderException("Invalid X.509 encoding of public key", e);
}
- return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
- privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
+ KeyStoreSecurityLevel securityLevel = iSecurityLevel;
+ if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {
+
+ return new AndroidKeyStoreECPublicKey(descriptor, metadata,
+ iSecurityLevel, (ECPublicKey) publicKey);
+ } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(jcaKeyAlgorithm)) {
+ return new AndroidKeyStoreRSAPublicKey(descriptor, metadata,
+ iSecurityLevel, (RSAPublicKey) publicKey);
+ } else {
+ throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+ + jcaKeyAlgorithm);
+ }
}
/** @hide **/
@NonNull
public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
+ @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- AndroidKeyStorePublicKey publicKey =
- loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
- keyCharacteristics);
- AndroidKeyStorePrivateKey privateKey =
- AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
- return new KeyPair(publicKey, privateKey);
+ AndroidKeyStoreKey key =
+ loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace);
+ if (key instanceof AndroidKeyStorePublicKey) {
+ return (AndroidKeyStorePublicKey) key;
+ } else {
+ throw new UnrecoverableKeyException("No asymmetric key found by the given alias.");
+ }
}
/** @hide **/
@NonNull
public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
+ @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
- keyCharacteristics);
- return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
+ AndroidKeyStoreKey key =
+ loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace);
+ if (key instanceof AndroidKeyStorePublicKey) {
+ AndroidKeyStorePublicKey publicKey = (AndroidKeyStorePublicKey) key;
+ return new KeyPair(publicKey, publicKey.getPrivateKey());
+ } else {
+ throw new UnrecoverableKeyException("No asymmetric key found by the given alias.");
+ }
}
/** @hide **/
@NonNull
public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
+ @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
+ AndroidKeyStoreKey key =
+ loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace);
+ if (key instanceof AndroidKeyStorePublicKey) {
+ return ((AndroidKeyStorePublicKey) key).getPrivateKey();
+ } else {
+ throw new UnrecoverableKeyException("No asymmetric key found by the given alias.");
+ }
}
+
@NonNull
- private static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
- @NonNull String secretKeyAlias, int uid, @NonNull KeyCharacteristics keyCharacteristics)
+ private static AndroidKeyStoreSecretKey makeAndroidKeyStoreSecretKeyFromKeyEntryResponse(
+ @NonNull KeyDescriptor descriptor,
+ @NonNull KeyEntryResponse response, int algorithm, int digest)
throws UnrecoverableKeyException {
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- List<Integer> keymasterDigests = keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST);
- int keymasterDigest;
- if (keymasterDigests.isEmpty()) {
- keymasterDigest = -1;
- } else {
- // More than one digest can be permitted for this key. Use the first one to form the
- // JCA key algorithm name.
- keymasterDigest = keymasterDigests.get(0);
- }
@KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
try {
keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- keymasterAlgorithm, keymasterDigest);
+ algorithm, digest);
} catch (IllegalArgumentException e) {
throw (UnrecoverableKeyException)
new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
}
- return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
+ return new AndroidKeyStoreSecretKey(descriptor,
+ response.metadata, keyAlgorithmString,
+ new KeyStoreSecurityLevel(response.iSecurityLevel));
}
- /** @hide **/
+ /**
+ * Loads an an AndroidKeyStoreKey from the AndroidKeyStore backend.
+ *
+ * @param keyStore The keystore2 backend.
+ * @param alias The alias of the key in the Keystore database.
+ * @param namespace The a Keystore namespace. This is used by system api only to request
+ * Android system specific keystore namespace, which can be configured
+ * in the device's SEPolicy. Third party apps and most system components
+ * set this parameter to -1 to indicate their application specific namespace.
+ * TODO b/171806779 link to public Keystore 2.0 documentation.
+ * See bug for more details for now.
+ * @hide
+ **/
@NonNull
public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String userKeyAlias, int uid)
+ @NonNull KeyStore2 keyStore, @NonNull String alias, int namespace)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- KeyCharacteristics keyCharacteristics = getKeyCharacteristics(keyStore, userKeyAlias, uid);
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
+ KeyDescriptor descriptor = new KeyDescriptor();
+ if (namespace == KeyProperties.NAMESPACE_APPLICATION) {
+ descriptor.nspace = 0; // ignored;
+ descriptor.domain = Domain.APP;
+ } else {
+ descriptor.nspace = namespace;
+ descriptor.domain = Domain.SELINUX;
+ }
+ descriptor.alias = alias;
+ descriptor.blob = null;
+ KeyEntryResponse response = null;
+ try {
+ response = keyStore.getKeyEntry(descriptor);
+ } catch (android.security.KeyStoreException e) {
+ if (e.getErrorCode() == ResponseCode.KEY_PERMANENTLY_INVALIDATED) {
+ throw new KeyPermanentlyInvalidatedException(
+ "User changed or deleted their auth credentials",
+ e);
+ } else {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain information about key")
+ .initCause(e);
+ }
+ }
+
+ Integer keymasterAlgorithm = null;
+ // We just need one digest for the algorithm name
+ int keymasterDigest = -1;
+ for (Authorization a : response.metadata.authorizations) {
+ switch (a.keyParameter.tag) {
+ case KeymasterDefs.KM_TAG_ALGORITHM:
+ keymasterAlgorithm = a.keyParameter.integer;
+ break;
+ case KeymasterDefs.KM_TAG_DIGEST:
+ if (keymasterDigest == -1) keymasterDigest = a.keyParameter.integer;
+ break;
+ }
+ }
if (keymasterAlgorithm == null) {
throw new UnrecoverableKeyException("Key algorithm unknown");
}
@@ -384,45 +375,15 @@ public class AndroidKeyStoreProvider extends Provider {
if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC ||
keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES ||
keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
- return loadAndroidKeyStoreSecretKeyFromKeystore(userKeyAlias, uid,
- keyCharacteristics);
+ return makeAndroidKeyStoreSecretKeyFromKeyEntryResponse(descriptor, response,
+ keymasterAlgorithm, keymasterDigest);
} else if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA ||
keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
- return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, userKeyAlias, uid,
- keyCharacteristics);
+ return makeAndroidKeyStorePublicKeyFromKeyEntryResponse(descriptor, response.metadata,
+ new KeyStoreSecurityLevel(response.iSecurityLevel),
+ keymasterAlgorithm);
} else {
throw new UnrecoverableKeyException("Key algorithm unknown");
}
}
-
- /**
- * 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.
- *
- * @param uid Uid for which the keystore provider is requested.
- * @throws KeyStoreException if a KeyStoreSpi implementation for the specified type is not
- * available from the specified provider.
- * @throws NoSuchProviderException If the specified provider is not registered in the security
- * provider list.
- * @hide
- */
- @SystemApi
- @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;
- }
}