Merge "Allow entropy to be provided to some operations"
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 3a23059..7be3a97 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -999,13 +999,15 @@
     };
 
     virtual int32_t generateKey(const String16& name, const KeymasterArguments& params,
-                                int uid, int flags, KeyCharacteristics* outCharacteristics)
+                                const uint8_t* entropy, size_t entropyLength, int uid, int flags,
+                                KeyCharacteristics* outCharacteristics)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
         data.writeString16(name);
         data.writeInt32(1);
         params.writeToParcel(&data);
+        data.writeByteArray(entropyLength, entropy);
         data.writeInt32(uid);
         data.writeInt32(flags);
         status_t status = remote()->transact(BnKeystoreService::GENERATE_KEY, data, &reply);
@@ -1131,7 +1133,8 @@
 
     virtual void begin(const sp<IBinder>& appToken, const String16& name,
                        keymaster_purpose_t purpose, bool pruneable,
-                       const KeymasterArguments& params, KeymasterArguments* outParams,
+                       const KeymasterArguments& params, const uint8_t* entropy,
+                       size_t entropyLength, KeymasterArguments* outParams,
                        OperationResult* result)
     {
         if (!result || !outParams) {
@@ -1145,6 +1148,7 @@
         data.writeInt32(pruneable ? 1 : 0);
         data.writeInt32(1);
         params.writeToParcel(&data);
+        data.writeByteArray(entropyLength, entropy);
         status_t status = remote()->transact(BnKeystoreService::BEGIN, data, &reply);
         if (status != NO_ERROR) {
             ALOGD("begin() could not contact remote: %d\n", status);
@@ -1584,10 +1588,14 @@
             if (data.readInt32() != 0) {
                 args.readFromParcel(data);
             }
+            const uint8_t* entropy = NULL;
+            size_t entropyLength = 0;
+            readByteArray(data, &entropy, &entropyLength);
             int32_t uid = data.readInt32();
             int32_t flags = data.readInt32();
             KeyCharacteristics outCharacteristics;
-            int32_t ret = generateKey(name, args, uid, flags, &outCharacteristics);
+            int32_t ret = generateKey(name, args, entropy, entropyLength, uid, flags,
+                                      &outCharacteristics);
             reply->writeNoException();
             reply->writeInt32(ret);
             reply->writeInt32(1);
@@ -1655,9 +1663,13 @@
             if (data.readInt32() != 0) {
                 args.readFromParcel(data);
             }
+            const uint8_t* entropy = NULL;
+            size_t entropyLength = 0;
+            readByteArray(data, &entropy, &entropyLength);
             KeymasterArguments outArgs;
             OperationResult result;
-            begin(token, name, purpose, pruneable, args, &outArgs, &result);
+            begin(token, name, purpose, pruneable, args, entropy, entropyLength, &outArgs,
+                  &result);
             reply->writeNoException();
             reply->writeInt32(1);
             result.writeToParcel(reply);
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index f7f1295..6cae3cb 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -197,11 +197,14 @@
     virtual int32_t addRngEntropy(const uint8_t* data, size_t dataLength) = 0;
 
     virtual int32_t generateKey(const String16& name, const KeymasterArguments& params,
-                                int uid, int flags, KeyCharacteristics* outCharacteristics) = 0;
+                                const uint8_t* entropy, size_t entropyLength, int uid, int flags,
+                                KeyCharacteristics* outCharacteristics) = 0;
+
     virtual int32_t getKeyCharacteristics(const String16& name,
                                           const keymaster_blob_t* clientId,
                                           const keymaster_blob_t* appData,
                                           KeyCharacteristics* outCharacteristics) = 0;
+
     virtual int32_t importKey(const String16& name, const KeymasterArguments&  params,
                               keymaster_key_format_t format, const uint8_t *keyData,
                               size_t keyLength, int uid, int flags,
@@ -213,7 +216,8 @@
 
     virtual void begin(const sp<IBinder>& apptoken, const String16& name,
                        keymaster_purpose_t purpose, bool pruneable,
-                       const KeymasterArguments& params, KeymasterArguments* outParams,
+                       const KeymasterArguments& params, const uint8_t* entropy,
+                       size_t entropyLength, KeymasterArguments* outParams,
                        OperationResult* result) = 0;
 
     virtual void update(const sp<IBinder>& token, const KeymasterArguments& params,
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index a949ffb..8523db6 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -2469,7 +2469,8 @@
     }
 
     int32_t generateKey(const String16& name, const KeymasterArguments& params,
-                        int uid, int flags, KeyCharacteristics* outCharacteristics) {
+                        const uint8_t* entropy, size_t entropyLength, 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)) {
@@ -2499,19 +2500,37 @@
         if (device == NULL) {
             return ::SYSTEM_ERROR;
         }
-        // TODO: Seed from Linux RNG either before this or periodically
+        // TODO: Seed from Linux RNG before this.
         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 (!entropy) {
+                rc = KM_ERROR_OK;
+            } else if (device->add_rng_entropy) {
+                rc = device->add_rng_entropy(device, entropy, entropyLength);
+            } else {
+                rc = KM_ERROR_UNIMPLEMENTED;
+            }
+            if (rc == KM_ERROR_OK) {
+                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 (!entropy) {
+                rc = KM_ERROR_OK;
+            } else if (fallback->add_rng_entropy) {
+                rc = fallback->add_rng_entropy(fallback, entropy, entropyLength);
+            } else {
+                rc = KM_ERROR_UNIMPLEMENTED;
+            }
+            if (rc == KM_ERROR_OK) {
+                rc = fallback->generate_key(fallback, params.params.data(), params.params.size(),
+                                            &blob,
+                                            &out);
+            }
         }
 
         if (out) {
@@ -2676,8 +2695,8 @@
     }
 
     void begin(const sp<IBinder>& appToken, const String16& name, keymaster_purpose_t purpose,
-               bool pruneable, const KeymasterArguments& params,
-               KeymasterArguments* outParams, OperationResult* result) {
+               bool pruneable, const KeymasterArguments& params, const uint8_t* entropy,
+               size_t entropyLength, KeymasterArguments* outParams, OperationResult* result) {
         if (!result || !outParams) {
             ALOGE("Unexpected null arguments to begin()");
             return;
@@ -2703,10 +2722,22 @@
         size_t outSize;
         keymaster_operation_handle_t handle;
         keymaster1_device_t* dev = mKeyStore->getDeviceForBlob(keyBlob);
+        keymaster_error_t err = KM_ERROR_UNIMPLEMENTED;
+        // Add entropy to the device first.
+        if (entropy) {
+            if (dev->add_rng_entropy) {
+                err = dev->add_rng_entropy(dev, entropy, entropyLength);
+            } else {
+                err = KM_ERROR_UNIMPLEMENTED;
+            }
+            if (err) {
+                result->resultCode = err;
+                return;
+            }
+        }
         // TODO: Check authorization.
-        keymaster_error_t err = dev->begin(dev, purpose, &key, params.params.data(),
-                                           params.params.size(), &out, &outSize,
-                                           &handle);
+        err = dev->begin(dev, purpose, &key, params.params.data(), params.params.size(), &out,
+                         &outSize, &handle);
 
         // If there are too many operations abort the oldest operation that was
         // started as pruneable and try again.