summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2015-07-16 16:32:23 -0700
committerAlex Klyubin <klyubin@google.com>2015-07-16 16:52:51 -0700
commita95550f8016bbb0dba086dbd73eec63e6cdbbe98 (patch)
treee6912c5fdb0fc66d6a5fc7fe48d3e8c640270877
parentf7592b234acde62f0f0a93dad77284f12ca9980a (diff)
downloadframeworks_base-a95550f8016bbb0dba086dbd73eec63e6cdbbe98.zip
frameworks_base-a95550f8016bbb0dba086dbd73eec63e6cdbbe98.tar.gz
frameworks_base-a95550f8016bbb0dba086dbd73eec63e6cdbbe98.tar.bz2
Add KM_MIN_MAC_LENGTH tag to HMAC and AES-GCM keys.
This makes Android Keystore add the KM_MIN_MAC_LENGTH tag to generated and imported HMAC and AES-GCM keys. This tag specifies the minimum length of the MAC/authentication tag authorized to be used for the key. For HMAC keys the minimum MAC length is set to the length of the digest associated with the key (HMAC keys are authorized for exactly one digest). For AES keys the minimum authetication tag length is set to 96 bit. This is the minimum supported by Android Keystore's AES-GCM implementation. Bug: 22337277 Change-Id: Ic6e47cf084734d1592788dc58088889f7fff74eb
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java6
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java2
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java7
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java5
-rw-r--r--keystore/java/android/security/keystore/KeymasterUtils.java43
5 files changed, 61 insertions, 2 deletions
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index bae5455..04d5952 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -51,6 +51,7 @@ public final class KeymasterDefs {
public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
public static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 7;
+ public static final int KM_TAG_MIN_MAC_LENGTH = KM_UINT | 8;
public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
@@ -194,6 +195,9 @@ public final class KeymasterDefs {
public static final int KM_ERROR_KEY_RATE_LIMIT_EXCEEDED = -54;
public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55;
public static final int KM_ERROR_KEY_MAX_OPS_EXCEEDED = -56;
+ public static final int KM_ERROR_INVALID_MAC_LENGTH = -57;
+ public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
+ public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
public static final int KM_ERROR_UNIMPLEMENTED = -100;
public static final int KM_ERROR_VERSION_MISMATCH = -101;
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -237,6 +241,8 @@ public final class KeymasterDefs {
sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV");
sErrorCodeToString.put(KM_ERROR_CALLER_NONCE_PROHIBITED,
"Caller-provided IV not permitted");
+ sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
+ "Invalid MAC or authentication tag length");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index 5459bea..441ee66 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -51,7 +51,7 @@ import javax.crypto.spec.GCMParameterSpec;
abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi {
- private static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
+ static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128;
private static final int DEFAULT_TAG_LENGTH_BITS = 128;
private static final int IV_LENGTH_BYTES = 12;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index fd014eb..4c174f1 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -171,7 +171,7 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
"Key size must be positive: " + mKeySizeBits);
} else if ((mKeySizeBits % 8) != 0) {
throw new InvalidAlgorithmParameterException(
- "Key size in must be a multiple of 8: " + mKeySizeBits);
+ "Key size must be a multiple of 8: " + mKeySizeBits);
}
try {
@@ -272,6 +272,11 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
KeymasterUtils.addUserAuthArgs(args,
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds());
+ KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
+ args,
+ mKeymasterAlgorithm,
+ mKeymasterBlockModes,
+ mKeymasterDigests);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
spec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 88858de..915d86f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -672,6 +672,11 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
KeymasterUtils.addUserAuthArgs(args,
params.isUserAuthenticationRequired(),
params.getUserAuthenticationValidityDurationSeconds());
+ KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
+ args,
+ keymasterAlgorithm,
+ keymasterBlockModes,
+ keymasterDigests);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
params.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 92d636c..feafbfa 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -22,6 +22,8 @@ import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
+import java.security.ProviderException;
+
/**
* @hide
*/
@@ -133,4 +135,45 @@ public abstract class KeymasterUtils {
userAuthenticationValidityDurationSeconds);
}
}
+
+ /**
+ * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
+ * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
+ * AES-GCM).
+ */
+ public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
+ int keymasterAlgorithm,
+ int[] keymasterBlockModes,
+ int[] keymasterDigests) {
+ switch (keymasterAlgorithm) {
+ case KeymasterDefs.KM_ALGORITHM_AES:
+ if (com.android.internal.util.ArrayUtils.contains(
+ keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
+ // AES GCM key needs the minimum length of AEAD tag specified.
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
+ AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
+ .MIN_SUPPORTED_TAG_LENGTH_BITS);
+ }
+ break;
+ case KeymasterDefs.KM_ALGORITHM_HMAC:
+ // HMAC key needs the minimum length of MAC set to the output size of the associated
+ // digest. This is because we do not offer a way to generate shorter MACs and
+ // don't offer a way to verify MACs (other than by generating them).
+ if (keymasterDigests.length != 1) {
+ throw new ProviderException(
+ "Unsupported number of authorized digests for HMAC key: "
+ + keymasterDigests.length
+ + ". Exactly one digest must be authorized");
+ }
+ int keymasterDigest = keymasterDigests[0];
+ int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
+ if (digestOutputSizeBits == -1) {
+ throw new ProviderException(
+ "HMAC key authorized for unsupported digest: "
+ + KeyProperties.Digest.fromKeymaster(keymasterDigest));
+ }
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
+ break;
+ }
+ }
}