Fix PayloadSignerTest.* in Brillo.

Added modules to install missing private and public keys.
There's no openssl binary in target device, rewrote SignHash() using
openssl library functions.

Test: GTEST_FILTER="PayloadSignerTest.*" ./update_engine_unittests
Bug: 26955860

Change-Id: Ie7f229d5456f641394fd57f5a6e9ca3cc5c5f0cd
diff --git a/Android.mk b/Android.mk
index c8bf904..c67ca22 100644
--- a/Android.mk
+++ b/Android.mk
@@ -688,6 +688,38 @@
 # dependencies are removed or placed behind the USE_DBUS flag.
 ifdef BRILLO
 
+# Private and public keys for unittests.
+# ========================================================
+# Generate a module that installs a prebuilt private key and a module that
+# installs a public key generated from the private key.
+#
+# $(1): The path to the private key in pem format.
+define ue-unittest-keys
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_MODULE := ue_$(1).pem) \
+    $(eval LOCAL_MODULE_CLASS := ETC) \
+    $(eval $(ifeq $(BRILLO), 1, LOCAL_MODULE_TAGS := eng)) \
+    $(eval LOCAL_SRC_FILES := $(1).pem) \
+    $(eval LOCAL_MODULE_PATH := \
+        $(TARGET_OUT_DATA_NATIVE_TESTS)/update_engine_unittests) \
+    $(eval LOCAL_MODULE_STEM := $(1).pem) \
+    $(eval include $(BUILD_PREBUILT)) \
+    \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_MODULE := ue_$(1).pub.pem) \
+    $(eval LOCAL_MODULE_CLASS := ETC) \
+    $(eval $(ifeq $(BRILLO), 1, LOCAL_MODULE_TAGS := eng)) \
+    $(eval LOCAL_MODULE_PATH := \
+        $(TARGET_OUT_DATA_NATIVE_TESTS)/update_engine_unittests) \
+    $(eval LOCAL_MODULE_STEM := $(1).pub.pem) \
+    $(eval include $(BUILD_SYSTEM)/base_rules.mk) \
+    $(eval $(LOCAL_BUILT_MODULE) : $(LOCAL_PATH)/$(1).pem ; \
+        openssl rsa -in $$< -pubout -out $$@)
+endef
+
+$(call ue-unittest-keys,unittest_key)
+$(call ue-unittest-keys,unittest_key2)
+
 # Sample images for unittests.
 # ========================================================
 # Generate a prebuilt module that installs a sample image from the compressed
@@ -747,7 +779,11 @@
     ue_unittest_disk_ext2_1k.img \
     ue_unittest_disk_ext2_4k.img \
     ue_unittest_disk_ext2_4k_empty.img \
-    ue_unittest_disk_ext2_unittest.img
+    ue_unittest_disk_ext2_unittest.img \
+    ue_unittest_key.pem \
+    ue_unittest_key.pub.pem \
+    ue_unittest_key2.pem \
+    ue_unittest_key2.pub.pem
 LOCAL_MODULE_CLASS := EXECUTABLES
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CLANG := true
diff --git a/payload_generator/payload_signer.cc b/payload_generator/payload_signer.cc
index a73b891..824195d 100644
--- a/payload_generator/payload_signer.cc
+++ b/payload_generator/payload_signer.cc
@@ -25,6 +25,7 @@
 #include <brillo/data_encoding.h>
 #include <brillo/streams/file_stream.h>
 #include <brillo/streams/stream.h>
+#include <openssl/err.h>
 #include <openssl/pem.h>
 
 #include "update_engine/common/hash_calculator.h"
@@ -346,34 +347,35 @@
                              const string& private_key_path,
                              brillo::Blob* out_signature) {
   LOG(INFO) << "Signing hash with private key: " << private_key_path;
-  string sig_path;
-  TEST_AND_RETURN_FALSE(
-      utils::MakeTempFile("signature.XXXXXX", &sig_path, nullptr));
-  ScopedPathUnlinker sig_path_unlinker(sig_path);
-
-  string hash_path;
-  TEST_AND_RETURN_FALSE(
-      utils::MakeTempFile("hash.XXXXXX", &hash_path, nullptr));
-  ScopedPathUnlinker hash_path_unlinker(hash_path);
   // We expect unpadded SHA256 hash coming in
   TEST_AND_RETURN_FALSE(hash.size() == 32);
   brillo::Blob padded_hash(hash);
   PayloadVerifier::PadRSA2048SHA256Hash(&padded_hash);
-  TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
-                                         padded_hash.data(),
-                                         padded_hash.size()));
 
-  // This runs on the server, so it's okay to copy out and call openssl
-  // executable rather than properly use the library.
-  vector<string> cmd = {"openssl", "rsautl", "-raw", "-sign", "-inkey",
-                        private_key_path, "-in", hash_path, "-out", sig_path};
-  int return_code = 0;
-  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code,
-                                                    nullptr));
-  TEST_AND_RETURN_FALSE(return_code == 0);
+  // The code below executes the equivalent of:
+  //
+  // openssl rsautl -raw -sign -inkey |private_key_path|
+  //   -in |padded_hash| -out |out_signature|
 
-  brillo::Blob signature;
-  TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
+  FILE* fprikey = fopen(private_key_path.c_str(), "rb");
+  TEST_AND_RETURN_FALSE(fprikey != nullptr);
+  RSA* rsa = PEM_read_RSAPrivateKey(fprikey, nullptr, nullptr, nullptr);
+  fclose(fprikey);
+  TEST_AND_RETURN_FALSE(rsa != nullptr);
+  brillo::Blob signature(RSA_size(rsa));
+  ssize_t signature_size = RSA_private_encrypt(padded_hash.size(),
+                                               padded_hash.data(),
+                                               signature.data(),
+                                               rsa,
+                                               RSA_NO_PADDING);
+  RSA_free(rsa);
+  if (signature_size < 0) {
+    LOG(ERROR) << "Signing hash failed: "
+               << ERR_error_string(ERR_get_error(), nullptr);
+    return false;
+  }
+  TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
+                        signature.size());
   out_signature->swap(signature);
   return true;
 }