OSDN Git Service

Make ImportWrappedKey work with real hardware:
authorFrank Salim <franksalim@google.com>
Thu, 12 Apr 2018 10:09:44 +0000 (03:09 -0700)
committerFrank Salim <franksalim@google.com>
Fri, 18 May 2018 18:25:33 +0000 (18:25 +0000)
  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

keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
keystore/java/android/security/keystore/KeyProtection.java

index cc80560..624321c 100644 (file)
@@ -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",
index 9b7695d..c048e82 100644 (file)
@@ -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");
index 3e9853c..2b5a37b 100644 (file)
@@ -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"
index fdcad85..081042b 100644 (file)
@@ -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;
     }
 
     /**
@@ -529,6 +532,14 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
     }
 
     /**
+     * Returns {@code true} if the key is protected by a Strongbox security chip.
+     * @hide
+     */
+    public boolean isStrongBoxBacked() {
+        return mIsStrongBoxBacked;
+    }
+
+    /**
      * Builder of {@link KeyProtection} instances.
      */
     public final static class Builder {
@@ -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}.
@@ -962,6 +974,16 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
         }
 
         /**
+         * 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}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -986,7 +1008,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
                     mBoundToSecureUserId,
                     mCriticalToDeviceEncryption,
                     mUserConfirmationRequired,
-                    mUnlockedDeviceRequired);
+                    mUnlockedDeviceRequired,
+                    mIsStrongBoxBacked);
         }
     }
 }