cryptfs: add support for keymaster 2

Change-Id: I1c4f06551897c8964ac2d40c9e785d527cc83847
diff --git a/crypto/fde/cryptfs.cpp b/crypto/fde/cryptfs.cpp
index 7c30eef..2d1595f 100644
--- a/crypto/fde/cryptfs.cpp
+++ b/crypto/fde/cryptfs.cpp
@@ -74,6 +74,7 @@
 #include <openssl/sha.h>
 #include <hardware/keymaster0.h>
 #include <hardware/keymaster1.h>
+#include <hardware/keymaster2.h>
 #endif
 //#include "android-base/properties.h"
 //#include <bootloader_message/bootloader_message.h>
@@ -176,7 +177,8 @@
 }
 #else //TW_KEYMASTER_MAX_API == 0
 static int keymaster_init(keymaster0_device_t **keymaster0_dev,
-                          keymaster1_device_t **keymaster1_dev)
+                          keymaster1_device_t **keymaster1_dev,
+			  keymaster2_device_t **keymaster2_dev)
 {
     int rc;
 
@@ -192,7 +194,11 @@
 
     *keymaster0_dev = NULL;
     *keymaster1_dev = NULL;
-    if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
+    *keymaster2_dev = NULL;
+    if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_2_0) {
+        printf("Found keymaster2 module, using keymaster2 API.\n");
+        rc = keymaster2_open(mod, keymaster2_dev);
+    } else if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
         printf("Found keymaster1 module, using keymaster1 API.\n");
         rc = keymaster1_open(mod, keymaster1_dev);
     } else {
@@ -211,6 +217,7 @@
 err:
     *keymaster0_dev = NULL;
     *keymaster1_dev = NULL;
+    *keymaster2_dev = NULL;
     return rc;
 }
 #endif //TW_KEYMASTER_MAX_API == 0
@@ -424,7 +431,8 @@
 #if TW_KEYMASTER_MAX_API >= 1
     keymaster0_device_t *keymaster0_dev = 0;
     keymaster1_device_t *keymaster1_dev = 0;
-    if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
+    keymaster2_device_t *keymaster2_dev = 0;
+    if (keymaster_init(&keymaster0_dev, &keymaster1_dev, &keymaster2_dev)) {
 #else
     keymaster_device_t *keymaster0_dev = 0;
     if (keymaster_init(&keymaster0_dev)) {
@@ -504,6 +512,82 @@
         *signature_size = tmp_sig.data_length;
         rc = 0;
     }
+    else if (keymaster2_dev) {
+        keymaster_key_blob_t key = { ftr->keymaster_blob, ftr->keymaster_blob_size };
+        keymaster_key_param_t params[] = {
+            keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
+            keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+        };
+        keymaster_key_param_set_t param_set = { params, sizeof(params)/sizeof(*params) };
+        keymaster_operation_handle_t op_handle;
+        keymaster_key_param_t config_params[] = {
+            // Set these to crazy values so we don't need to synchronize
+            // the recovery with system updates.
+            // key upgrades will be required; it will be upgraded in-memory
+            keymaster_param_int(KM_TAG_OS_VERSION, 999999),
+	    keymaster_param_int(KM_TAG_OS_PATCHLEVEL, 209912),
+        };
+        keymaster_key_param_set_t config_param_set = { config_params, sizeof(config_params)/sizeof(*config_params) };
+        keymaster2_dev->configure(keymaster2_dev, &config_param_set);
+        keymaster_error_t error = keymaster2_dev->begin(keymaster2_dev, KM_PURPOSE_SIGN, &key,
+                                                        &param_set, NULL /* out_params */,
+                                                        &op_handle);
+        if (error == KM_ERROR_KEY_RATE_LIMIT_EXCEEDED) {
+            // Key usage has been rate-limited.  Wait a bit and try again.
+            sleep(KEYMASTER_CRYPTFS_RATE_LIMIT);
+            error = keymaster2_dev->begin(keymaster2_dev, KM_PURPOSE_SIGN, &key,
+                                          &param_set, NULL /* out_params */,
+                                          &op_handle);
+        }
+
+        if (error == KM_ERROR_KEY_REQUIRES_UPGRADE) {
+            // Upgrade key in-memory if required
+            // Do not actually write it back; just keep it in memory
+            const keymaster_key_blob_t key_to_upd = key;
+            keymaster2_dev->upgrade_key(keymaster2_dev, &key_to_upd, &config_param_set, &key);
+            error = keymaster2_dev->begin(keymaster2_dev, KM_PURPOSE_SIGN, &key,
+                                          &param_set, NULL /* out_params */,
+                                          &op_handle);
+        }
+
+        if (error != KM_ERROR_OK) {
+            printf("Error starting keymaster signature transaction: %d\n", error);
+            rc = -1;
+            goto out;
+        }
+
+        keymaster_blob_t input = { to_sign, to_sign_size };
+        size_t input_consumed;
+        error = keymaster2_dev->update(keymaster2_dev, op_handle, NULL /* in_params */,
+                                       &input, &input_consumed, NULL /* out_params */,
+                                       NULL /* output */);
+        if (error != KM_ERROR_OK) {
+            printf("Error sending data to keymaster signature transaction: %d\n", error);
+            rc = -1;
+            goto out;
+        }
+        if (input_consumed != to_sign_size) {
+            // This should never happen.  If it does, it's a bug in the keymaster implementation.
+            printf("Keymaster update() did not consume all data.\n");
+            keymaster2_dev->abort(keymaster2_dev, op_handle);
+            rc = -1;
+            goto out;
+        }
+
+        keymaster_blob_t tmp_sig;
+        error = keymaster2_dev->finish(keymaster2_dev, op_handle, NULL /* in_params */,
+                                       NULL, NULL /* verify signature */, NULL /* out_params */,
+                                       &tmp_sig);
+        if (error != KM_ERROR_OK) {
+            printf("Error finishing keymaster signature transaction: %d\n", error);
+            rc = -1;
+            goto out;
+        }
+
+        *signature = (uint8_t*)tmp_sig.data;
+        *signature_size = tmp_sig.data_length;
+        rc = 0;
+    }
 #endif // TW_KEYMASTER_API >= 1
 
     out:
@@ -949,7 +1033,9 @@
   tgt->next = crypt_params - buffer;
 
   for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
-    if (! ioctl(fd, DM_TABLE_LOAD, io)) {
+    int ret = ioctl(fd, DM_TABLE_LOAD, io);
+    if (!ret)  {
+      SLOGI("ioctl err: %d", ret);
       break;
     }
     usleep(500000);