Verify AU payload manifest signature if present.

In order to support downloads over http for a number of reasons, we need
to secure http downloads. The first step in this process is to
verify the signature of the manifest itself before parsing. This can be
done even for https-based downloads in order to provide defense-in-depth
against a SSL attack. This CL adds the required verification logic in
update_engine, if such a manifest signature is present in the Omaha
response.

Until the delta generator is modified in a subsequent check-in to update
the manifest and payload with the required signature, none of this new
code will have any effect.

The delta generator change to populate non-zero values for these new
fields will follow in subsequent CLs.

BUG=chromium-os:33602
TEST=Tested on ZGB to make sure existing functionality works fine.
     Added new unit tests.
Change-Id: I2d8b09c23faf87049893b1dee97a34e1f300aded
Reviewed-on: https://gerrit.chromium.org/gerrit/32844
Commit-Ready: Jay Srinivasan <jaysri@chromium.org>
Reviewed-by: Jay Srinivasan <jaysri@chromium.org>
Tested-by: Jay Srinivasan <jaysri@chromium.org>
diff --git a/delta_performer.h b/delta_performer.h
index dd8f8d8..8ea30c3 100644
--- a/delta_performer.h
+++ b/delta_performer.h
@@ -13,6 +13,7 @@
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 #include "update_engine/file_writer.h"
+#include "update_engine/install_plan.h"
 #include "update_engine/omaha_hash_calculator.h"
 #include "update_engine/update_metadata.pb.h"
 
@@ -33,8 +34,9 @@
 
   static const char kUpdatePayloadPublicKeyPath[];
 
-  DeltaPerformer(PrefsInterface* prefs)
+  DeltaPerformer(PrefsInterface* prefs, InstallPlan* install_plan)
       : prefs_(prefs),
+        install_plan_(install_plan),
         fd_(-1),
         kernel_fd_(-1),
         manifest_valid_(false),
@@ -42,7 +44,8 @@
         next_operation_num_(0),
         buffer_offset_(0),
         last_updated_buffer_offset_(kuint64max),
-        block_size_(0) {}
+        block_size_(0),
+        public_key_path_(kUpdatePayloadPublicKeyPath) {}
 
   // Opens the kernel. Should be called before or after Open(), but before
   // Write(). The kernel file will be close()d when Close() is called.
@@ -52,24 +55,29 @@
   // Open()ed again.
   int Open(const char* path, int flags, mode_t mode);
 
-  // Wrapper around write. Returns true if all requested bytes
-  // were written, or false on any error, reguardless of progress.
-  bool Write(const void* bytes, size_t count);
+  // FileWriter's Write implementation where caller doesn't care about
+  // error codes.
+  bool Write(const void* bytes, size_t count) {
+    ActionExitCode error;
+    return Write(bytes, count, &error);
+  }
+
+  // FileWriter's Write implementation that returns a more specific |error| code
+  // in case of failures in Write operation.
+  bool Write(const void* bytes, size_t count, ActionExitCode *error);
 
   // Wrapper around close. Returns 0 on success or -errno on error.
   // Closes both 'path' given to Open() and the kernel path.
   int Close();
 
   // Verifies the downloaded payload against the signed hash included in the
-  // payload, against the update check hash and size, and against the public
-  // key and returns kActionCodeSuccess on success, an error code on failure.
-  // This method should be called after closing the stream. Note this method
-  // skips the signed hash check if the public key is unavailable; it returns
-  // kActionCodeSignedDeltaPayloadExpectedError if the public key
-  // is available but the delta payload doesn't include a signature. If
-  // |public_key_path| is an empty string, uses the default public key path.
-  ActionExitCode VerifyPayload(const std::string& public_key_path,
-                               const std::string& update_check_response_hash,
+  // payload, against the update check hash (which is in base64 format)  and
+  // size using the public key and returns kActionCodeSuccess on success, an
+  // error code on failure.  This method should be called after closing the
+  // stream. Note this method skips the signed hash check if the public key is
+  // unavailable; it returns kActionCodeSignedDeltaPayloadExpectedError if the
+  // public key is available but the delta payload doesn't include a signature.
+  ActionExitCode VerifyPayload(const std::string& update_check_response_hash,
                                const uint64_t update_check_response_size);
 
   // Reads from the update manifest the expected sizes and hashes of the target
@@ -115,17 +123,14 @@
   // returns kMetadataParseSuccess. Returns kMetadataParseInsufficientData if
   // more data is needed to parse the complete metadata. Returns
   // kMetadataParseError if the metadata can't be parsed given the payload.
-  static MetadataParseResult ParsePayloadMetadata(
+  MetadataParseResult ParsePayloadMetadata(
       const std::vector<char>& payload,
       DeltaArchiveManifest* manifest,
-      uint64_t* metadata_size);
+      uint64_t* metadata_size,
+      ActionExitCode* error);
 
-  void set_current_kernel_hash(const std::vector<char>& hash) {
-    current_kernel_hash_ = hash;
-  }
-
-  void set_current_rootfs_hash(const std::vector<char>& hash) {
-    current_rootfs_hash_ = hash;
+  void set_public_key_path(const std::string& public_key_path) {
+    public_key_path_ = public_key_path;
   }
 
  private:
@@ -146,6 +151,23 @@
   bool CanPerformInstallOperation(
       const DeltaArchiveManifest_InstallOperation& operation);
 
+  // Validates that the hash of the blobs corresponding to the given |operation|
+  // matches what's specified in the manifest in the payload.
+  // Returns kActionCodeSuccess on match or a suitable error code otherwise.
+  ActionExitCode ValidateOperationHash(
+      const DeltaArchiveManifest_InstallOperation& operation);
+
+  // Interprets the given |protobuf| as a DeltaArchiveManifest protocol buffer
+  // of the given protobuf_length and verifies that the signed hash of the
+  // manifest matches what's specified in the install plan from Omaha.
+  // Returns kActionCodeSuccess on match or a suitable error code otherwise.
+  // This method must be called before any part of the |protobuf| is parsed
+  // so that a man-in-the-middle attack on the SSL connection to the payload
+  // server doesn't exploit any vulnerability in the code that parses the
+  // protocol buffer.
+  ActionExitCode ValidateManifestSignature(const char* protobuf,
+                                           uint64_t protobuf_length);
+
   // Returns true on success.
   bool PerformInstallOperation(
       const DeltaArchiveManifest_InstallOperation& operation);
@@ -182,6 +204,9 @@
   // Update Engine preference store.
   PrefsInterface* prefs_;
 
+  // Install Plan based on Omaha Response.
+  InstallPlan* install_plan_;
+
   // File descriptor of open device.
   int fd_;
 
@@ -221,10 +246,9 @@
   // Signatures message blob extracted directly from the payload.
   std::vector<char> signatures_message_data_;
 
-  // Hashes for the current partitions to be used for source partition
-  // verification.
-  std::vector<char> current_kernel_hash_;
-  std::vector<char> current_rootfs_hash_;
+  // The public key to be used. Provided as a member so that tests can
+  // override with test keys.
+  std::string public_key_path_;
 
   DISALLOW_COPY_AND_ASSIGN(DeltaPerformer);
 };