summaryrefslogtreecommitdiffstats
path: root/keystore
diff options
context:
space:
mode:
Diffstat (limited to 'keystore')
-rw-r--r--keystore/java/android/security/KeyChain.java19
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java6
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java21
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java7
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java9
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java15
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java174
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java6
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java4
-rw-r--r--keystore/java/android/security/keystore/KeymasterUtils.java4
10 files changed, 155 insertions, 110 deletions
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index f482bf0..7de26d6 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -17,6 +17,7 @@ package android.security;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.WorkerThread;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -351,11 +352,15 @@ public final class KeyChain {
* Returns the {@code PrivateKey} for the requested alias, or null
* if no there is no result.
*
- * @param alias The alias of the desired private key, typically
- * returned via {@link KeyChainAliasCallback#alias}.
+ * <p> This method may block while waiting for a connection to another process, and must never
+ * be called from the main thread.
+ *
+ * @param alias The alias of the desired private key, typically returned via
+ * {@link KeyChainAliasCallback#alias}.
* @throws KeyChainException if the alias was valid but there was some problem accessing it.
+ * @throws IllegalStateException if called from the main thread.
*/
- @Nullable
+ @Nullable @WorkerThread
public static PrivateKey getPrivateKey(@NonNull Context context, @NonNull String alias)
throws KeyChainException, InterruptedException {
if (alias == null) {
@@ -386,11 +391,15 @@ public final class KeyChain {
* Returns the {@code X509Certificate} chain for the requested
* alias, or null if no there is no result.
*
+ * <p> This method may block while waiting for a connection to another process, and must never
+ * be called from the main thread.
+ *
* @param alias The alias of the desired certificate chain, typically
* returned via {@link KeyChainAliasCallback#alias}.
* @throws KeyChainException if the alias was valid but there was some problem accessing it.
+ * @throws IllegalStateException if called from the main thread.
*/
- @Nullable
+ @Nullable @WorkerThread
public static X509Certificate[] getCertificateChain(@NonNull Context context,
@NonNull String alias) throws KeyChainException, InterruptedException {
if (alias == null) {
@@ -505,6 +514,7 @@ public final class KeyChain {
*
* Caller should call unbindService on the result when finished.
*/
+ @WorkerThread
public static KeyChainConnection bind(@NonNull Context context) throws InterruptedException {
return bindAsUser(context, Process.myUserHandle());
}
@@ -512,6 +522,7 @@ public final class KeyChain {
/**
* @hide
*/
+ @WorkerThread
public static KeyChainConnection bindAsUser(@NonNull Context context, UserHandle user)
throws InterruptedException {
if (context == null) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index 6411066..5459bea 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -129,6 +129,12 @@ abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreC
return;
}
+ if (!"GCM".equalsIgnoreCase(params.getAlgorithm())) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
+ + ". Supported: GCM");
+ }
+
GCMParameterSpec spec;
try {
spec = params.getParameterSpec(GCMParameterSpec.class);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
index 515be1d..5ce4fd2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
@@ -124,22 +124,27 @@ public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
@Override
protected PrivateKey engineGeneratePrivate(KeySpec spec) throws InvalidKeySpecException {
- throw new UnsupportedOperationException(
- "To generate a key pair in Android KeyStore, use KeyPairGenerator initialized with"
+ throw new InvalidKeySpecException(
+ "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
+ " " + KeyGenParameterSpec.class.getName());
}
@Override
protected PublicKey engineGeneratePublic(KeySpec spec) throws InvalidKeySpecException {
- throw new UnsupportedOperationException(
- "To generate a key pair in Android KeyStore, use KeyPairGenerator initialized with"
+ throw new InvalidKeySpecException(
+ "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
+ " " + KeyGenParameterSpec.class.getName());
}
@Override
- protected Key engineTranslateKey(Key arg0) throws InvalidKeyException {
- throw new UnsupportedOperationException(
- "To import a key into Android KeyStore, use KeyStore.setEntry with "
- + KeyProtection.class.getName());
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ } else if ((!(key instanceof AndroidKeyStorePrivateKey))
+ && (!(key instanceof AndroidKeyStorePublicKey))) {
+ throw new InvalidKeyException(
+ "To import a key into Android Keystore, use KeyStore.setEntry");
+ }
+ return key;
}
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 258133d..6a7930a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -239,6 +239,13 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
"At least one digest algorithm must be specified");
}
}
+
+ // Check that user authentication related parameters are acceptable. This method
+ // will throw an IllegalStateException if there are issues (e.g., secure lock screen
+ // not set up).
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
+ spec.isUserAuthenticationRequired(),
+ spec.getUserAuthenticationValidityDurationSeconds());
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 459514d..6b36a58 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -310,7 +310,14 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
} else {
mKeymasterDigests = EmptyArray.INT;
}
- } catch (IllegalArgumentException e) {
+
+ // Check that user authentication related parameters are acceptable. This method
+ // will throw an IllegalStateException if there are issues (e.g., secure lock screen
+ // not set up).
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
+ mSpec.isUserAuthenticationRequired(),
+ mSpec.getUserAuthenticationValidityDurationSeconds());
+ } catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 9a2f908..11c22a9 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -185,15 +185,20 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
@Override
protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
- throw new UnsupportedOperationException(
- "To generate secret key in Android KeyStore, use KeyGenerator initialized with "
+ throw new InvalidKeySpecException(
+ "To generate secret key in Android Keystore, use KeyGenerator initialized with "
+ KeyGenParameterSpec.class.getName());
}
@Override
protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
- throw new UnsupportedOperationException(
- "To import a secret key into Android KeyStore, use KeyStore.setEntry with "
- + KeyProtection.class.getName());
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
+ throw new InvalidKeyException(
+ "To import a secret key into Android Keystore, use KeyStore.setEntry");
+ }
+
+ return key;
}
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index dc8f1e3..e9f19cd 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -484,8 +484,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
spec.getKeyValidityForOriginationEnd());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
spec.getKeyValidityForConsumptionEnd());
- } catch (IllegalArgumentException e) {
- throw new KeyStoreException("Invalid parameter", e);
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ throw new KeyStoreException(e);
}
}
@@ -598,102 +598,100 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
+ " RAW format export");
}
- String keyAlgorithmString = key.getAlgorithm();
- int keymasterAlgorithm;
- int keymasterDigest;
- try {
- keymasterAlgorithm =
- KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(keyAlgorithmString);
- keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(keyAlgorithmString);
- } catch (IllegalArgumentException e) {
- throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
- }
-
KeymasterArguments args = new KeymasterArguments();
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
-
- int[] keymasterDigests;
- if (params.isDigestsSpecified()) {
- // Digest(s) specified in parameters
- keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
- if (keymasterDigest != -1) {
- // Digest also specified in the JCA key algorithm name.
- if (!com.android.internal.util.ArrayUtils.contains(
- keymasterDigests, keymasterDigest)) {
- throw new KeyStoreException("Key digest mismatch"
- + ". Key: " + keyAlgorithmString
- + ", parameter spec: " + Arrays.asList(params.getDigests()));
- }
- // When the key is read back from keystore we reconstruct the JCA key algorithm
- // name from the KM_TAG_ALGORITHM and the first KM_TAG_DIGEST. Thus we need to
- // ensure that the digest reflected in the JCA key algorithm name is the first
- // KM_TAG_DIGEST tag.
- if (keymasterDigests[0] != keymasterDigest) {
- // The first digest is not the one implied by the JCA key algorithm name.
- // Swap the implied digest with the first one.
- for (int i = 0; i < keymasterDigests.length; i++) {
- if (keymasterDigests[i] == keymasterDigest) {
- keymasterDigests[i] = keymasterDigests[0];
- keymasterDigests[0] = keymasterDigest;
- break;
+ try {
+ int keymasterAlgorithm =
+ KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(key.getAlgorithm());
+ args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
+
+ int[] keymasterDigests;
+ int keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
+ if (params.isDigestsSpecified()) {
+ // Digest(s) specified in parameters
+ keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
+ if (keymasterDigest != -1) {
+ // Digest also specified in the JCA key algorithm name.
+ if (!com.android.internal.util.ArrayUtils.contains(
+ keymasterDigests, keymasterDigest)) {
+ throw new KeyStoreException("Digest specified in key algorithm "
+ + key.getAlgorithm() + " not specified in protection parameters: "
+ + Arrays.asList(params.getDigests()));
+ }
+ // When the key is read back from keystore we reconstruct the JCA key algorithm
+ // name from the KM_TAG_ALGORITHM and the first KM_TAG_DIGEST. Thus we need to
+ // ensure that the digest reflected in the JCA key algorithm name is the first
+ // KM_TAG_DIGEST tag.
+ if (keymasterDigests[0] != keymasterDigest) {
+ // The first digest is not the one implied by the JCA key algorithm name.
+ // Swap the implied digest with the first one.
+ for (int i = 0; i < keymasterDigests.length; i++) {
+ if (keymasterDigests[i] == keymasterDigest) {
+ keymasterDigests[i] = keymasterDigests[0];
+ keymasterDigests[0] = keymasterDigest;
+ break;
+ }
}
}
}
- }
- } else {
- // No digest specified in parameters
- if (keymasterDigest != -1) {
- // Digest specified in the JCA key algorithm name.
- keymasterDigests = new int[] {keymasterDigest};
} else {
- keymasterDigests = EmptyArray.INT;
+ // No digest specified in parameters
+ if (keymasterDigest != -1) {
+ // Digest specified in the JCA key algorithm name.
+ keymasterDigests = new int[] {keymasterDigest};
+ } else {
+ keymasterDigests = EmptyArray.INT;
+ }
}
- }
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
- if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- if (keymasterDigests.length == 0) {
- throw new KeyStoreException("At least one digest algorithm must be specified"
- + " for key algorithm " + keyAlgorithmString);
+ args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
+ if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+ if (keymasterDigests.length == 0) {
+ throw new KeyStoreException("At least one digest algorithm must be specified"
+ + " for key algorithm " + key.getAlgorithm());
+ }
}
- }
- @KeyProperties.PurposeEnum int purposes = params.getPurposes();
- int[] keymasterBlockModes =
- KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (params.isRandomizedEncryptionRequired())) {
- for (int keymasterBlockMode : keymasterBlockModes) {
- if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
- keymasterBlockMode)) {
- throw new KeyStoreException(
- "Randomized encryption (IND-CPA) required but may be violated by block"
- + " mode: "
- + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
- + ". See KeyProtection documentation.");
+ @KeyProperties.PurposeEnum int purposes = params.getPurposes();
+ int[] keymasterBlockModes =
+ KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
+ if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
+ && (params.isRandomizedEncryptionRequired())) {
+ for (int keymasterBlockMode : keymasterBlockModes) {
+ if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
+ keymasterBlockMode)) {
+ throw new KeyStoreException(
+ "Randomized encryption (IND-CPA) required but may be violated by"
+ + " block mode: "
+ + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
+ + ". See KeyProtection documentation.");
+ }
}
}
- }
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, KeyProperties.Purpose.allToKeymaster(purposes));
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
- if (params.getSignaturePaddings().length > 0) {
- throw new KeyStoreException("Signature paddings not supported for symmetric keys");
- }
- int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
- params.getEncryptionPaddings());
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
- KeymasterUtils.addUserAuthArgs(args,
- params.isUserAuthenticationRequired(),
- params.getUserAuthenticationValidityDurationSeconds());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- params.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- params.getKeyValidityForConsumptionEnd());
-
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (!params.isRandomizedEncryptionRequired())) {
- // Permit caller-provided IV when encrypting with this key
- args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
+ args.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
+ KeyProperties.Purpose.allToKeymaster(purposes));
+ args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
+ if (params.getSignaturePaddings().length > 0) {
+ throw new KeyStoreException("Signature paddings not supported for symmetric keys");
+ }
+ int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
+ params.getEncryptionPaddings());
+ args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
+ KeymasterUtils.addUserAuthArgs(args,
+ params.isUserAuthenticationRequired(),
+ params.getUserAuthenticationValidityDurationSeconds());
+ args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
+ params.getKeyValidityStart());
+ args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+ params.getKeyValidityForOriginationEnd());
+ args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+ params.getKeyValidityForConsumptionEnd());
+
+ if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
+ && (!params.isRandomizedEncryptionRequired())) {
+ // Permit caller-provided IV when encrypting with this key
+ args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
+ }
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ throw new KeyStoreException(e);
}
Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
index 486519c..1f1d36f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
@@ -197,6 +197,12 @@ class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSp
return;
}
+ if (!"AES".equalsIgnoreCase(params.getAlgorithm())) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
+ + ". Supported: AES");
+ }
+
IvParameterSpec ivSpec;
try {
ivSpec = params.getParameterSpec(IvParameterSpec.class);
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index f9fe176..2b49297 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -210,10 +210,6 @@ public abstract class KeyProperties {
int keymasterAlgorithm, int keymasterDigest) {
switch (keymasterAlgorithm) {
case KeymasterDefs.KM_ALGORITHM_AES:
- if (keymasterDigest != -1) {
- throw new IllegalArgumentException("Digest not supported for AES key: "
- + Digest.fromKeymaster(keymasterDigest));
- }
return KEY_ALGORITHM_AES;
case KeymasterDefs.KM_ALGORITHM_HMAC:
switch (keymasterDigest) {
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 3cd3f2a..92d636c 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -87,6 +87,10 @@ public abstract class KeymasterUtils {
* @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user
* authentication is valid as authorization for using the key or {@code -1} if every
* use of the key needs authorization.
+ *
+ * @throws IllegalStateException if user authentication is required but the system is in a wrong
+ * state (e.g., secure lock screen not set up) for generating or importing keys that
+ * require user authentication.
*/
public static void addUserAuthArgs(KeymasterArguments args,
boolean userAuthenticationRequired,