summaryrefslogtreecommitdiffstats
path: root/keystore
diff options
context:
space:
mode:
Diffstat (limited to 'keystore')
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java54
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java66
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java3
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java3
4 files changed, 55 insertions, 71 deletions
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 6a7930a..fd014eb 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -197,48 +197,36 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
}
}
}
- if (spec.isDigestsSpecified()) {
- // Digest(s) explicitly specified in the spec
- mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
- if (mKeymasterDigest != -1) {
- // Key algorithm implies a digest -- ensure it's specified in the spec as
- // first digest.
- if (!com.android.internal.util.ArrayUtils.contains(
- mKeymasterDigests, mKeymasterDigest)) {
+
+ if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+ // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
+ // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
+ // one digest, we don't let algorithm parameter spec override the digest implied
+ // by the key. If the spec specifies digests at all, it must specify only one
+ // digest, the only implied by key algorithm.
+ mKeymasterDigests = new int[] {mKeymasterDigest};
+ if (spec.isDigestsSpecified()) {
+ // Digest(s) explicitly specified in the spec. Check that the list
+ // consists of exactly one digest, the one implied by key algorithm.
+ int[] keymasterDigestsFromSpec =
+ KeyProperties.Digest.allToKeymaster(spec.getDigests());
+ if ((keymasterDigestsFromSpec.length != 1)
+ || (keymasterDigestsFromSpec[0] != mKeymasterDigest)) {
throw new InvalidAlgorithmParameterException(
- "Digests specified in algorithm parameters ("
- + Arrays.asList(spec.getDigests()) + ") must include "
- + " the digest "
+ "Unsupported digests specification: "
+ + Arrays.asList(spec.getDigests()) + ". Only "
+ KeyProperties.Digest.fromKeymaster(mKeymasterDigest)
- + " implied by key algorithm");
- }
- if (mKeymasterDigests[0] != mKeymasterDigest) {
- // The first digest is not the one implied by the key algorithm.
- // Swap the implied digest with the first one.
- for (int i = 0; i < mKeymasterDigests.length; i++) {
- if (mKeymasterDigests[i] == mKeymasterDigest) {
- mKeymasterDigests[i] = mKeymasterDigests[0];
- mKeymasterDigests[0] = mKeymasterDigest;
- break;
- }
- }
+ + " supported for this HMAC key algorithm");
}
}
} else {
- // No digest specified in the spec
- if (mKeymasterDigest != -1) {
- // Key algorithm implies a digest -- use that digest
- mKeymasterDigests = new int[] {mKeymasterDigest};
+ // Key algorithm does not imply a digest.
+ if (spec.isDigestsSpecified()) {
+ mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
} else {
mKeymasterDigests = EmptyArray.INT;
}
}
- if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- if (mKeymasterDigests.length == 0) {
- throw new InvalidAlgorithmParameterException(
- "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
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index e9f19cd..88858de 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -41,6 +41,7 @@ import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.ProviderException;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
@@ -605,50 +606,43 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
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;
- }
- }
+ if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+ // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
+ // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
+ // digest, we don't let import parameters override the digest implied by the key.
+ // If the parameters specify digests at all, they must specify only one digest, the
+ // only implied by key algorithm.
+ int keymasterImpliedDigest =
+ KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
+ if (keymasterImpliedDigest == -1) {
+ throw new ProviderException(
+ "HMAC key algorithm digest unknown for key algorithm "
+ + key.getAlgorithm());
+ }
+ keymasterDigests = new int[] {keymasterImpliedDigest};
+ if (params.isDigestsSpecified()) {
+ // Digest(s) explicitly specified in params -- check that the list consists of
+ // exactly one digest, the one implied by key algorithm.
+ int[] keymasterDigestsFromParams =
+ KeyProperties.Digest.allToKeymaster(params.getDigests());
+ if ((keymasterDigestsFromParams.length != 1)
+ || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
+ throw new KeyStoreException(
+ "Unsupported digests specification: "
+ + Arrays.asList(params.getDigests()) + ". Only "
+ + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest)
+ + " supported for HMAC key algorithm " + key.getAlgorithm());
}
}
} else {
- // No digest specified in parameters
- if (keymasterDigest != -1) {
- // Digest specified in the JCA key algorithm name.
- keymasterDigests = new int[] {keymasterDigest};
+ // Key algorithm does not imply a digest.
+ if (params.isDigestsSpecified()) {
+ keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
} 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 " + key.getAlgorithm());
- }
- }
@KeyProperties.PurposeEnum int purposes = params.getPurposes();
int[] keymasterBlockModes =
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 919dd48..faaa1a6 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -642,7 +642,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
* <p>This must be specified for signing/verification keys and RSA encryption/decryption
* keys used with RSA OAEP padding scheme because these operations involve a digest. For
* HMAC keys, the default is the digest associated with the key algorithm (e.g.,
- * {@code SHA-256} for key algorithm {@code HmacSHA256}).
+ * {@code SHA-256} for key algorithm {@code HmacSHA256}). HMAC keys cannot be authorized
+ * for more than one digest.
*
* <p>For private keys used for TLS/SSL client or server authentication it is usually
* necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 5b4b3e7..ec0ef24 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -423,7 +423,8 @@ public final class KeyProtection implements ProtectionParameter {
* <p>This must be specified for signing/verification keys and RSA encryption/decryption
* keys used with RSA OAEP padding scheme because these operations involve a digest. For
* HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()} (e.g.,
- * {@code SHA-256} for key algorithm {@code HmacSHA256}).
+ * {@code SHA-256} for key algorithm {@code HmacSHA256}). HMAC keys cannot be authorized
+ * for more than one digest.
*
* <p>For private keys used for TLS/SSL client or server authentication it is usually
* necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is