diff options
author | Janis Danisevskis <jdanis@google.com> | 2020-10-06 21:46:18 -0700 |
---|---|---|
committer | Janis Danisevskis <jdanis@google.com> | 2020-11-13 19:55:40 -0800 |
commit | e6495d774b4e310aed99820cfe5a6ea731a9d2fb (patch) | |
tree | 7e23f164c246a22e433356394aabd77882e364e8 | |
parent | 38ab78f0a0b8e123022fe52a7a8ff0943ddd3690 (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.java | 20 | ||||
-rw-r--r-- | keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java | 251 |
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 { |