summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanis Danisevskis <jdanis@google.com>2020-10-06 21:46:18 -0700
committerJanis Danisevskis <jdanis@google.com>2020-11-13 19:55:40 -0800
commite6495d774b4e310aed99820cfe5a6ea731a9d2fb (patch)
tree7e23f164c246a22e433356394aabd77882e364e8
parent38ab78f0a0b8e123022fe52a7a8ff0943ddd3690 (diff)
Keystore 2.0 SPI: Evolve Factory SPI
We no longer need to get the key characteristics from the Keystore daemon to construct the KeyInfo for a key. Also we have to extract the key info from the KeyParameter AIDL type rather than from the hand written KeymasterArguments. This patch also exposes the correct security level for a key through KeyInfo. Bug: 159476414 Test: None Change-Id: I86a85e481e19fdadfed38a42aeac4ffe5f8b83fa
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java20
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java251
2 files changed, 141 insertions, 130 deletions
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java
index 607bcae6570d..a8dd7f3f8b14 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java
@@ -16,7 +16,6 @@
package android.security.keystore2;
-import android.security.Credentials;
import android.security.KeyStore;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyInfo;
@@ -64,18 +63,9 @@ public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
"Unsupported key type: " + key.getClass().getName()
+ ". KeyInfo can be obtained only for Android Keystore private keys");
}
- 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());
- } else {
- throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
- }
+ AndroidKeyStorePrivateKey keystorePrivateKey = (AndroidKeyStorePrivateKey) key;
@SuppressWarnings("unchecked")
- T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(
- mKeyStore, entryAlias, keyAliasInKeystore, keystorePrivateKey.getUid());
+ T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(keystorePrivateKey);
return result;
} else if (X509EncodedKeySpec.class.equals(keySpecClass)) {
if (!(key instanceof AndroidKeyStorePublicKey)) {
@@ -98,8 +88,7 @@ public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
}
} else if (RSAPublicKeySpec.class.equals(keySpecClass)) {
if (key instanceof AndroidKeyStoreRSAPublicKey) {
- AndroidKeyStoreRSAPublicKey
- rsaKey = (AndroidKeyStoreRSAPublicKey) key;
+ AndroidKeyStoreRSAPublicKey rsaKey = (AndroidKeyStoreRSAPublicKey) key;
@SuppressWarnings("unchecked")
T result =
(T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent());
@@ -112,8 +101,7 @@ public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
}
} else if (ECPublicKeySpec.class.equals(keySpecClass)) {
if (key instanceof AndroidKeyStoreECPublicKey) {
- AndroidKeyStoreECPublicKey
- ecKey = (AndroidKeyStoreECPublicKey) key;
+ AndroidKeyStoreECPublicKey ecKey = (AndroidKeyStoreECPublicKey) key;
@SuppressWarnings("unchecked")
T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
return result;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
index c2a8e10c1e51..9d3b9704d711 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -16,13 +16,15 @@
package android.security.keystore2;
-import android.security.Credentials;
+import android.annotation.NonNull;
import android.security.GateKeeper;
import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyInfo;
+import android.security.keystore.KeyProperties;
+import android.system.keystore2.Authorization;
import java.math.BigInteger;
import java.security.InvalidKeyException;
@@ -64,137 +66,161 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
}
AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key;
- String keyAliasInKeystore = keystoreKey.getAlias();
- String entryAlias;
- if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
- } else if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)){
- // key has legacy prefix
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
- } else {
- throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
- }
- return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid());
+ return getKeyInfo(keystoreKey);
}
- static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore,
- int keyUid) {
- KeyCharacteristics keyCharacteristics = new 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);
- }
+ static @NonNull KeyInfo getKeyInfo(@NonNull AndroidKeyStoreKey key) {
- boolean insideSecureHardware;
- @KeyProperties.OriginEnum int origin;
- int keySize;
- @KeyProperties.PurposeEnum int purposes;
+ @KeyProperties.SecurityLevelEnum int securityLevel =
+ KeyProperties.SECURITY_LEVEL_SOFTWARE;
+ boolean insideSecureHardware = false;
+ @KeyProperties.OriginEnum int origin = -1;
+ int keySize = -1;
+ @KeyProperties.PurposeEnum int purposes = 0;
String[] encryptionPaddings;
String[] signaturePaddings;
- @KeyProperties.DigestEnum String[] digests;
- @KeyProperties.BlockModeEnum String[] blockModes;
- int keymasterSwEnforcedUserAuthenticators;
- int keymasterHwEnforcedUserAuthenticators;
- List<BigInteger> keymasterSecureUserIds;
+ List<String> digestsList = new ArrayList<>();
+ List<String> blockModesList = new ArrayList<>();
+ int keymasterSwEnforcedUserAuthenticators = 0;
+ int keymasterHwEnforcedUserAuthenticators = 0;
+ List<BigInteger> keymasterSecureUserIds = new ArrayList<BigInteger>();
+ List<String> encryptionPaddingsList = new ArrayList<String>();
+ List<String> signaturePaddingsList = new ArrayList<String>();
+ Date keyValidityStart = null;
+ Date keyValidityForOriginationEnd = null;
+ Date keyValidityForConsumptionEnd = null;
+ long userAuthenticationValidityDurationSeconds = 0;
+ boolean userAuthenticationRequired = true;
+ boolean userAuthenticationValidWhileOnBody = false;
+ boolean trustedUserPresenceRequired = false;
+ boolean trustedUserConfirmationRequired = false;
try {
- if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
- insideSecureHardware = true;
- origin = KeyProperties.Origin.fromKeymaster(
- keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
- } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
- insideSecureHardware = false;
- origin = KeyProperties.Origin.fromKeymaster(
- keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
- } else {
- throw new ProviderException("Key origin not available");
- }
- long keySizeUnsigned =
- keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
- if (keySizeUnsigned == -1) {
- throw new ProviderException("Key size not available");
- } else if (keySizeUnsigned > Integer.MAX_VALUE) {
- throw new ProviderException("Key too large: " + keySizeUnsigned + " bits");
- }
- keySize = (int) keySizeUnsigned;
- purposes = KeyProperties.Purpose.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PURPOSE));
-
- List<String> encryptionPaddingsList = new ArrayList<String>();
- List<String> signaturePaddingsList = new ArrayList<String>();
- // Keymaster stores both types of paddings in the same array -- we split it into two.
- for (int keymasterPadding : keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PADDING)) {
- try {
- @KeyProperties.EncryptionPaddingEnum String jcaPadding =
- KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
- encryptionPaddingsList.add(jcaPadding);
- } catch (IllegalArgumentException e) {
- try {
- @KeyProperties.SignaturePaddingEnum String padding =
- KeyProperties.SignaturePadding.fromKeymaster(keymasterPadding);
- signaturePaddingsList.add(padding);
- } catch (IllegalArgumentException e2) {
- throw new ProviderException(
- "Unsupported encryption padding: " + keymasterPadding);
- }
+ for (Authorization a : key.getAuthorizations()) {
+ switch (a.keyParameter.tag) {
+ case KeymasterDefs.KM_TAG_ORIGIN:
+ insideSecureHardware =
+ KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
+ securityLevel = a.securityLevel;
+ origin = KeyProperties.Origin.fromKeymaster(a.keyParameter.integer);
+ break;
+ case KeymasterDefs.KM_TAG_KEY_SIZE:
+ long keySizeUnsigned = KeyStore2ParameterUtils.getUnsignedInt(a);
+ if (keySizeUnsigned > Integer.MAX_VALUE) {
+ throw new ProviderException(
+ "Key too large: " + keySizeUnsigned + " bits");
+ }
+ keySize = (int) keySizeUnsigned;
+ break;
+ case KeymasterDefs.KM_TAG_PURPOSE:
+ purposes |= KeyProperties.Purpose.fromKeymaster(a.keyParameter.integer);
+ break;
+ case KeymasterDefs.KM_TAG_PADDING:
+ try {
+ if (a.keyParameter.integer == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN
+ || a.keyParameter.integer == KeymasterDefs.KM_PAD_RSA_PSS) {
+ @KeyProperties.SignaturePaddingEnum String padding =
+ KeyProperties.SignaturePadding.fromKeymaster(
+ a.keyParameter.integer);
+ signaturePaddingsList.add(padding);
+ } else {
+ @KeyProperties.EncryptionPaddingEnum String jcaPadding =
+ KeyProperties.EncryptionPadding.fromKeymaster(
+ a.keyParameter.integer);
+ encryptionPaddingsList.add(jcaPadding);
+ }
+ } catch (IllegalArgumentException e) {
+ throw new ProviderException("Unsupported padding: "
+ + a.keyParameter.integer);
+ }
+ break;
+ case KeymasterDefs.KM_TAG_DIGEST:
+ digestsList.add(KeyProperties.Digest.fromKeymaster(a.keyParameter.integer));
+ break;
+ case KeymasterDefs.KM_TAG_BLOCK_MODE:
+ blockModesList.add(
+ KeyProperties.BlockMode.fromKeymaster(a.keyParameter.integer)
+ );
+ break;
+ case KeymasterDefs.KM_TAG_USER_AUTH_TYPE:
+ if (KeyStore2ParameterUtils.isSecureHardware(a.securityLevel)) {
+ keymasterHwEnforcedUserAuthenticators = a.keyParameter.integer;
+ } else {
+ keymasterSwEnforcedUserAuthenticators = a.keyParameter.integer;
+ }
+ break;
+ case KeymasterDefs.KM_TAG_USER_SECURE_ID:
+ keymasterSecureUserIds.add(
+ KeymasterArguments.toUint64(a.keyParameter.longInteger));
+ break;
+ case KeymasterDefs.KM_TAG_ACTIVE_DATETIME:
+ keyValidityStart = KeyStore2ParameterUtils.getDate(a);
+ break;
+ case KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+ keyValidityForOriginationEnd =
+ KeyStore2ParameterUtils.getDate(a);
+ break;
+ case KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME:
+ keyValidityForConsumptionEnd =
+ KeyStore2ParameterUtils.getDate(a);
+ break;
+ case KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED:
+ userAuthenticationRequired = false;
+ break;
+ case KeymasterDefs.KM_TAG_AUTH_TIMEOUT:
+ userAuthenticationValidityDurationSeconds =
+ KeyStore2ParameterUtils.getUnsignedInt(a);
+ if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) {
+ throw new ProviderException(
+ "User authentication timeout validity too long: "
+ + userAuthenticationValidityDurationSeconds + " seconds");
+ }
+ break;
+ case KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY:
+ userAuthenticationValidWhileOnBody =
+ KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
+ break;
+ case KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+ trustedUserPresenceRequired =
+ KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
+ break;
+ case KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
+ trustedUserConfirmationRequired =
+ KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
+ break;
}
-
}
- encryptionPaddings =
- encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
- signaturePaddings =
- signaturePaddingsList.toArray(new String[signaturePaddingsList.size()]);
-
- digests = KeyProperties.Digest.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST));
- blockModes = KeyProperties.BlockMode.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_BLOCK_MODE));
- keymasterSwEnforcedUserAuthenticators =
- keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- keymasterHwEnforcedUserAuthenticators =
- keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- keymasterSecureUserIds =
- keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
} catch (IllegalArgumentException e) {
throw new ProviderException("Unsupported key characteristic", e);
}
-
- Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
- Date keyValidityForOriginationEnd =
- keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
- Date keyValidityForConsumptionEnd =
- keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
- boolean userAuthenticationRequired =
- !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
- long userAuthenticationValidityDurationSeconds =
- keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, 0);
- if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) {
- throw new ProviderException("User authentication timeout validity too long: "
- + userAuthenticationValidityDurationSeconds + " seconds");
+ if (keySize == -1) {
+ throw new ProviderException("Key size not available");
}
+ if (origin == -1) {
+ throw new ProviderException("Key origin not available");
+ }
+
+ encryptionPaddings =
+ encryptionPaddingsList.toArray(new String[0]);
+ signaturePaddings =
+ signaturePaddingsList.toArray(new String[0]);
+
boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
&& (keymasterHwEnforcedUserAuthenticators != 0)
&& (keymasterSwEnforcedUserAuthenticators == 0);
- boolean userAuthenticationValidWhileOnBody =
- keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
- boolean trustedUserPresenceRequired =
- keyCharacteristics.hwEnforced.getBoolean(
- KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+
+ String[] digests = digestsList.toArray(new String[0]);
+ String[] blockModes = blockModesList.toArray(new String[0]);
boolean invalidatedByBiometricEnrollment = false;
if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC
|| keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC) {
// Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
- invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
- && !keymasterSecureUserIds.isEmpty()
+ invalidatedByBiometricEnrollment = !keymasterSecureUserIds.isEmpty()
&& !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
}
- boolean userConfirmationRequired = keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
-
- return new KeyInfo(entryAlias,
+ return new KeyInfo(key.getUserKeyDescriptor().alias,
insideSecureHardware,
origin,
keySize,
@@ -213,11 +239,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
userAuthenticationValidWhileOnBody,
trustedUserPresenceRequired,
invalidatedByBiometricEnrollment,
- userConfirmationRequired,
- // Keystore 1.0 does not tell us the exact security level of the key
- // so we assume TEE if the key is in secure hardware.
- insideSecureHardware ? KeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT
- : KeyProperties.SecurityLevelEnum.SOFTWARE);
+ trustedUserConfirmationRequired,
+ securityLevel);
}
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {