Refactor GoogleKeymaster to move openssl RSA key-generation operations
to RsaOperation.

Change-Id: Id6c66bd431cf3f8895113108027920ffafef578b
diff --git a/rsa_operation.cpp b/rsa_operation.cpp
index 620df65..ce9a58c 100644
--- a/rsa_operation.cpp
+++ b/rsa_operation.cpp
@@ -22,10 +22,60 @@
 namespace keymaster {
 
 struct EVP_PKEY_Delete {
-    void operator()(EVP_PKEY* p) const {
-        EVP_PKEY_free(p);
-    }
+    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
 };
+struct BIGNUM_Delete {
+    void operator()(BIGNUM* p) const { BN_free(p); }
+};
+
+struct RSA_Delete {
+    void operator()(RSA* p) const { RSA_free(p); }
+};
+
+/**
+ * Many OpenSSL APIs take ownership of an argument on success but don't free the argument on
+ * failure. This means we need to tell our scoped pointers when we've transferred ownership, without
+ * triggering a warning by not using the result of release().
+ */
+template <typename T, typename Delete_T>
+inline void release_because_ownership_transferred(UniquePtr<T, Delete_T>& p) {
+    T* val __attribute__((unused)) = p.release();
+}
+
+/* static */
+keymaster_error_t RsaOperation::Generate(uint64_t public_exponent, uint32_t key_size,
+                                         UniquePtr<uint8_t[]>* key_data, size_t* key_data_size) {
+    if (key_data == NULL || key_data_size == NULL)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new());
+    UniquePtr<RSA, RSA_Delete> rsa_key(RSA_new());
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    if (rsa_key.get() == NULL || pkey.get() == NULL)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (!BN_set_word(exponent.get(), public_exponent) ||
+        !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    if (!EVP_PKEY_assign_RSA(pkey.get(), rsa_key.get()))
+        return KM_ERROR_UNKNOWN_ERROR;
+    else
+        release_because_ownership_transferred(rsa_key);
+
+    *key_data_size = i2d_PrivateKey(pkey.get(), NULL);
+    if (*key_data_size <= 0)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    key_data->reset(new uint8_t[*key_data_size]);
+    if (key_data->get() == NULL)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* tmp = key_data->get();
+    i2d_PrivateKey(pkey.get(), &tmp);
+
+    return KM_ERROR_OK;
+}
 
 RsaOperation::RsaOperation(keymaster_purpose_t purpose, const KeyBlob& key)
     : Operation(purpose), rsa_key_(NULL) {