From 4b9fee53319e4f679af51681c8a90777f302bdfc Mon Sep 17 00:00:00 2001 From: Frank Salim Date: Thu, 12 Apr 2018 03:09:44 -0700 Subject: [PATCH] Make ImportWrappedKey work with real hardware: Get unwrapping params from WrappedKeyEntry Add @hide API for StrongBox-backed imported keys (as opposed to wrapped or generated) Enable 3DES conditionally based on a system property. Bug: b/79986479 Bug: b/79986680 Test: CTS Change-Id: If6beedc203337027576ecd3555d11ed2874f9768 --- .../AndroidKeyStoreBCWorkaroundProvider.java | 4 +- .../keystore/AndroidKeyStoreProvider.java | 5 +- .../security/keystore/AndroidKeyStoreSpi.java | 74 +++++++++++++++++-- .../security/keystore/KeyProtection.java | 27 ++++++- 4 files changed, 101 insertions(+), 9 deletions(-) diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java index cc805605bdf8d..624321cbf5ea0 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java @@ -48,6 +48,8 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { private static final String KEYSTORE_PUBLIC_KEY_CLASS_NAME = PACKAGE_NAME + ".AndroidKeyStorePublicKey"; + private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede"; + AndroidKeyStoreBCWorkaroundProvider() { super("AndroidKeyStoreBCWorkaround", 1.0, @@ -93,7 +95,7 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSymmetricCipherImpl("AES/CTR/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding"); - if ("true".equals(System.getProperty("supports3DES"))) { + if ("true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY))) { putSymmetricCipherImpl("DESede/CBC/NoPadding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding"); putSymmetricCipherImpl("DESede/CBC/PKCS7Padding", diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java index 9b7695daf5ffa..c048e82092a1f 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java @@ -64,10 +64,13 @@ public class AndroidKeyStoreProvider extends Provider { private static final String PACKAGE_NAME = "android.security.keystore"; + private static final String DESEDE_SYSTEM_PROPERTY = + "ro.hardware.keystore_desede"; + public AndroidKeyStoreProvider() { super(PROVIDER_NAME, 1.0, "Android KeyStore security provider"); - boolean supports3DES = "true".equals(System.getProperty("supports3DES")); + boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY)); // java.security.KeyStore put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi"); diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index 3e9853c455e5b..2b5a37bd84e28 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -353,6 +353,10 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { if (spec.isCriticalToDeviceEncryption()) { flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION; } + + if (spec.isStrongBoxBacked()) { + flags |= KeyStore.FLAG_STRONGBOX; + } } else { throw new KeyStoreException( "Unsupported protection parameter class:" + param.getClass().getName() @@ -720,6 +724,9 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { if (params.isCriticalToDeviceEncryption()) { flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION; } + if (params.isStrongBoxBacked()) { + flags |= KeyStore.FLAG_STRONGBOX; + } Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid); String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + entryAlias; @@ -737,19 +744,76 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } } - private void setWrappedKeyEntry(String alias, byte[] wrappedKeyBytes, String wrappingKeyAlias, + private void setWrappedKeyEntry(String alias, WrappedKeyEntry entry, java.security.KeyStore.ProtectionParameter param) throws KeyStoreException { if (param != null) { throw new KeyStoreException("Protection parameters are specified inside wrapped keys"); } byte[] maskingKey = new byte[32]; - KeymasterArguments args = new KeymasterArguments(); // TODO: populate wrapping key args. + + + KeymasterArguments args = new KeymasterArguments(); + String[] parts = entry.getTransformation().split("/"); + + String algorithm = parts[0]; + if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) { + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA); + } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) { + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA); + } + + if (parts.length > 1) { + String mode = parts[1]; + if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(mode)) { + args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB); + } else if (KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(mode)) { + args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CBC); + } else if (KeyProperties.BLOCK_MODE_CTR.equalsIgnoreCase(mode)) { + args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR); + } else if (KeyProperties.BLOCK_MODE_GCM.equalsIgnoreCase(mode)) { + args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM); + } + } + + if (parts.length > 2) { + String padding = parts[2]; + if (KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) { + // Noop + } else if (KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) { + args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7); + } else if (KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) { + args.addEnums(KeymasterDefs.KM_TAG_PADDING, + KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + } else if (KeyProperties.ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) { + args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP); + } + } + + KeyGenParameterSpec spec = (KeyGenParameterSpec) entry.getAlgorithmParameterSpec(); + if (spec.isDigestsSpecified()) { + String digest = spec.getDigests()[0]; + if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) { + // Noop + } else if (KeyProperties.DIGEST_MD5.equalsIgnoreCase(digest)) { + args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5); + } else if (KeyProperties.DIGEST_SHA1.equalsIgnoreCase(digest)) { + args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1); + } else if (KeyProperties.DIGEST_SHA224.equalsIgnoreCase(digest)) { + args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224); + } else if (KeyProperties.DIGEST_SHA256.equalsIgnoreCase(digest)) { + args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256); + } else if (KeyProperties.DIGEST_SHA384.equalsIgnoreCase(digest)) { + args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384); + } else if (KeyProperties.DIGEST_SHA512.equalsIgnoreCase(digest)) { + args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512); + } + } int errorCode = mKeyStore.importWrappedKey( Credentials.USER_SECRET_KEY + alias, - wrappedKeyBytes, - Credentials.USER_PRIVATE_KEY + wrappingKeyAlias, + entry.getWrappedKeyBytes(), + Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(), maskingKey, args, GateKeeper.getSecureUserId(), @@ -996,7 +1060,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { setSecretKeyEntry(alias, secE.getSecretKey(), param); } else if (entry instanceof WrappedKeyEntry) { WrappedKeyEntry wke = (WrappedKeyEntry) entry; - setWrappedKeyEntry(alias, wke.getWrappedKeyBytes(), wke.getWrappingKeyAlias(), param); + setWrappedKeyEntry(alias, wke, param); } else { throw new KeyStoreException( "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry" diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index fdcad85bd70d7..081042b4d7fc1 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -232,6 +232,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { private final boolean mCriticalToDeviceEncryption; private final boolean mUserConfirmationRequired; private final boolean mUnlockedDeviceRequired; + private final boolean mIsStrongBoxBacked; private KeyProtection( Date keyValidityStart, @@ -251,7 +252,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { long boundToSecureUserId, boolean criticalToDeviceEncryption, boolean userConfirmationRequired, - boolean unlockedDeviceRequired) { + boolean unlockedDeviceRequired, + boolean isStrongBoxBacked) { mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); @@ -272,6 +274,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { mCriticalToDeviceEncryption = criticalToDeviceEncryption; mUserConfirmationRequired = userConfirmationRequired; mUnlockedDeviceRequired = unlockedDeviceRequired; + mIsStrongBoxBacked = isStrongBoxBacked; } /** @@ -528,6 +531,14 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { return mUnlockedDeviceRequired; } + /** + * Returns {@code true} if the key is protected by a Strongbox security chip. + * @hide + */ + public boolean isStrongBoxBacked() { + return mIsStrongBoxBacked; + } + /** * Builder of {@link KeyProtection} instances. */ @@ -552,6 +563,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID; private boolean mCriticalToDeviceEncryption = false; + private boolean mIsStrongBoxBacked = false; /** * Creates a new instance of the {@code Builder}. @@ -961,6 +973,16 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { return this; } + /** + * Sets whether this key should be protected by a StrongBox security chip. + * @hide + */ + @NonNull + public Builder setIsStrongBoxBacked(boolean isStrongBoxBacked) { + mIsStrongBoxBacked = isStrongBoxBacked; + return this; + } + /** * Builds an instance of {@link KeyProtection}. * @@ -986,7 +1008,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { mBoundToSecureUserId, mCriticalToDeviceEncryption, mUserConfirmationRequired, - mUnlockedDeviceRequired); + mUnlockedDeviceRequired, + mIsStrongBoxBacked); } } }