Implement keymaster 1.0 generate_key method

Change-Id: Ib63de5d9ee8da60599af2e644122ac6777720c8c
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 4c139bc..c17eacc 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -489,6 +489,7 @@
     TYPE_GENERIC = 1,
     TYPE_MASTER_KEY = 2,
     TYPE_KEY_PAIR = 3,
+    TYPE_KEYMASTER_10 = 4,
 } BlobType;
 
 static const uint8_t CURRENT_BLOB_VERSION = 2;
@@ -1173,6 +1174,15 @@
                 }
             }
         }
+        if (keyBlob.getType() == ::TYPE_KEYMASTER_10) {
+            keymaster1_device_t* dev = getDeviceForBlob(keyBlob);
+            if (dev->delete_key) {
+                keymaster_key_blob_t blob;
+                blob.key_material = keyBlob.getValue();
+                blob.key_material_size = keyBlob.getLength();
+                dev->delete_key(dev, &blob);
+            }
+        }
         if (rc != ::NO_ERROR) {
             return rc;
         }
@@ -1701,7 +1711,7 @@
 
         String8 name8(name);
         String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
-        return mKeyStore->del(filename.string(), ::TYPE_GENERIC, targetUid);
+        return mKeyStore->del(filename.string(), ::TYPE_ANY, targetUid);
     }
 
     int32_t exist(const String16& name, int targetUid) {
@@ -2453,9 +2463,77 @@
         return ::NO_ERROR;
     }
 
-    int32_t generateKey(const String16& /*name*/, const KeymasterArguments& /*params*/,
-                        int /*uid*/, int /*flags*/, KeyCharacteristics* /*outCharacteristics*/) {
-        return KM_ERROR_UNIMPLEMENTED;
+    int32_t generateKey(const String16& name, const KeymasterArguments& params,
+                        int uid, int flags, KeyCharacteristics* outCharacteristics) {
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        pid_t callingPid = IPCThreadState::self()->getCallingPid();
+        if (!has_permission(callingUid, P_INSERT, callingPid)) {
+            ALOGW("permission denied for %d: generateKey", callingUid);
+            return ::PERMISSION_DENIED;
+        }
+
+        State state = mKeyStore->getState(callingUid);
+        if ((flags & KEYSTORE_FLAG_ENCRYPTED) && !isKeystoreUnlocked(state)) {
+            ALOGW("calling generate in state: %d", state);
+            return state;
+        }
+
+        if (uid == -1) {
+            uid = callingUid;
+        } else if (!is_granted_to(callingUid, uid)) {
+            return ::PERMISSION_DENIED;
+        }
+
+        uint8_t* data;
+        size_t dataLength;
+        int rc = KM_ERROR_UNIMPLEMENTED;
+        bool isFallback = false;
+        keymaster_key_blob_t blob;
+        keymaster_key_characteristics_t *out = NULL;
+
+        const keymaster1_device_t* device = mKeyStore->getDevice();
+        const keymaster1_device_t* fallback = mKeyStore->getFallbackDevice();
+        if (device == NULL) {
+            return ::SYSTEM_ERROR;
+        }
+        // TODO: Seed from Linux RNG either before this or periodically
+        if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0 &&
+                device->generate_key != NULL) {
+            rc = device->generate_key(device, params.params.data(), params.params.size(), &blob,
+                                      &out);
+        }
+        // If the HW device didn't support generate_key or generate_key failed
+        // fall back to the software implementation.
+        if (rc && fallback->generate_key != NULL) {
+            isFallback = true;
+            rc = fallback->generate_key(fallback, params.params.data(), params.params.size(),
+                                      &blob,
+                                      &out);
+        }
+
+        if (out) {
+            if (outCharacteristics) {
+                outCharacteristics->characteristics = *out;
+            } else {
+                keymaster_free_characteristics(out);
+            }
+            free(out);
+        }
+
+        if (rc) {
+            return rc;
+        }
+
+        String8 name8(name);
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid));
+
+        Blob keyBlob(blob.key_material, blob.key_material_size, NULL, 0, ::TYPE_KEYMASTER_10);
+        keyBlob.setFallback(isFallback);
+        keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+        free(const_cast<uint8_t*>(blob.key_material));
+
+        return mKeyStore->put(filename.string(), &keyBlob, uid);
     }
 
     int32_t getKeyCharacteristics(const String16& /*name*/,