Merge "Add metadata signature size field in payload major version 2."
diff --git a/bzip_extent_writer.h b/bzip_extent_writer.h
index d854dd2..6941c66 100644
--- a/bzip_extent_writer.h
+++ b/bzip_extent_writer.h
@@ -18,6 +18,7 @@
 #define UPDATE_ENGINE_BZIP_EXTENT_WRITER_H_
 
 #include <bzlib.h>
+#include <memory>
 #include <vector>
 
 #include <chromeos/secure_blob.h>
@@ -33,19 +34,20 @@
 
 class BzipExtentWriter : public ExtentWriter {
  public:
-  explicit BzipExtentWriter(ExtentWriter* next) : next_(next) {
+  explicit BzipExtentWriter(std::unique_ptr<ExtentWriter> next)
+      : next_(std::move(next)) {
     memset(&stream_, 0, sizeof(stream_));
   }
-  ~BzipExtentWriter() {}
+  ~BzipExtentWriter() override = default;
 
   bool Init(FileDescriptorPtr fd,
             const std::vector<Extent>& extents,
-            uint32_t block_size);
-  bool Write(const void* bytes, size_t count);
-  bool EndImpl();
+            uint32_t block_size) override;
+  bool Write(const void* bytes, size_t count) override;
+  bool EndImpl() override;
 
  private:
-  ExtentWriter* const next_;  // The underlying ExtentWriter.
+  std::unique_ptr<ExtentWriter> next_;  // The underlying ExtentWriter.
   bz_stream stream_;  // the libbz2 stream
   chromeos::Blob input_buffer_;
 };
diff --git a/bzip_extent_writer_unittest.cc b/bzip_extent_writer_unittest.cc
index 14e821a..986be9f 100644
--- a/bzip_extent_writer_unittest.cc
+++ b/bzip_extent_writer_unittest.cc
@@ -20,10 +20,14 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+
 #include <algorithm>
 #include <string>
 #include <vector>
+
+#include <chromeos/make_unique_ptr.h>
 #include <gtest/gtest.h>
+
 #include "update_engine/test_utils.h"
 #include "update_engine/utils.h"
 
@@ -74,8 +78,8 @@
     0x22, 0x9c, 0x28, 0x48, 0x66, 0x61, 0xb8, 0xea, 0x00,
   };
 
-  DirectExtentWriter direct_writer;
-  BzipExtentWriter bzip_writer(&direct_writer);
+  BzipExtentWriter bzip_writer(
+      chromeos::make_unique_ptr(new DirectExtentWriter()));
   EXPECT_TRUE(bzip_writer.Init(fd_, extents, kBlockSize));
   EXPECT_TRUE(bzip_writer.Write(test, sizeof(test)));
   EXPECT_TRUE(bzip_writer.End());
@@ -114,8 +118,8 @@
   chromeos::Blob compressed_data;
   EXPECT_TRUE(utils::ReadFile(compressed_path, &compressed_data));
 
-  DirectExtentWriter direct_writer;
-  BzipExtentWriter bzip_writer(&direct_writer);
+  BzipExtentWriter bzip_writer(
+      chromeos::make_unique_ptr(new DirectExtentWriter()));
   EXPECT_TRUE(bzip_writer.Init(fd_, extents, kBlockSize));
 
   chromeos::Blob original_compressed_data = compressed_data;
diff --git a/delta_performer.cc b/delta_performer.cc
index 194f934..0071834 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -30,6 +30,7 @@
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <chromeos/data_encoding.h>
+#include <chromeos/make_unique_ptr.h>
 #include <google/protobuf/repeated_field.h>
 
 #include "update_engine/bzip_extent_writer.h"
@@ -50,7 +51,6 @@
 using google::protobuf::RepeatedPtrField;
 using std::min;
 using std::string;
-using std::unique_ptr;
 using std::vector;
 
 namespace chromeos_update_engine {
@@ -660,21 +660,13 @@
   // Extract the signature message if it's in this operation.
   ExtractSignatureMessage(operation);
 
-  DirectExtentWriter direct_writer;
-  ZeroPadExtentWriter zero_pad_writer(&direct_writer);
-  unique_ptr<BzipExtentWriter> bzip_writer;
+  // Setup the ExtentWriter stack based on the operation type.
+  std::unique_ptr<ExtentWriter> writer =
+    chromeos::make_unique_ptr(new ZeroPadExtentWriter(
+      chromeos::make_unique_ptr(new DirectExtentWriter())));
 
-  // Since bzip decompression is optional, we have a variable writer that will
-  // point to one of the ExtentWriter objects above.
-  ExtentWriter* writer = nullptr;
-  if (operation.type() == InstallOperation::REPLACE) {
-    writer = &zero_pad_writer;
-  } else if (operation.type() == InstallOperation::REPLACE_BZ) {
-    bzip_writer.reset(new BzipExtentWriter(&zero_pad_writer));
-    writer = bzip_writer.get();
-  } else {
-    NOTREACHED();
-  }
+  if (operation.type() == InstallOperation::REPLACE_BZ)
+    writer.reset(new BzipExtentWriter(std::move(writer)));
 
   // Create a vector of extents to pass to the ExtentWriter.
   vector<Extent> extents;
@@ -1234,29 +1226,22 @@
   }
   TEST_AND_RETURN_VAL(ErrorCode::kSignedDeltaPayloadExpectedError,
                       !signatures_message_data_.empty());
-  chromeos::Blob signed_hash_data;
-  TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
-                      PayloadVerifier::VerifySignature(
-                          signatures_message_data_,
-                          path_to_public_key.value(),
-                          &signed_hash_data));
   OmahaHashCalculator signed_hasher;
   TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
                       signed_hasher.SetContext(signed_hash_context_));
   TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
                       signed_hasher.Finalize());
   chromeos::Blob hash_data = signed_hasher.raw_hash();
-  PayloadVerifier::PadRSA2048SHA256Hash(&hash_data);
+  TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
+                      PayloadVerifier::PadRSA2048SHA256Hash(&hash_data));
   TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
                       !hash_data.empty());
-  if (hash_data != signed_hash_data) {
+
+  if (!PayloadVerifier::VerifySignature(
+      signatures_message_data_, path_to_public_key.value(), hash_data)) {
     // The autoupdate_CatchBadSignatures test checks for this string
     // in log-files. Keep in sync.
-    LOG(ERROR) << "Public key verification failed, thus update failed. "
-        "Attached Signature:";
-    utils::HexDumpVector(signed_hash_data);
-    LOG(ERROR) << "Computed Signature:";
-    utils::HexDumpVector(hash_data);
+    LOG(ERROR) << "Public key verification failed, thus update failed.";
     return ErrorCode::kDownloadPayloadPubKeyVerificationError;
   }
 
diff --git a/delta_performer_integration_test.cc b/delta_performer_integration_test.cc
index 1e3dea8..eddce9c 100644
--- a/delta_performer_integration_test.cc
+++ b/delta_performer_integration_test.cc
@@ -193,8 +193,7 @@
       out_metadata_size));
   EXPECT_TRUE(PayloadVerifier::VerifySignedPayload(
       payload_path,
-      kUnittestPublicKeyPath,
-      kSignatureMessageOriginalVersion));
+      kUnittestPublicKeyPath));
 }
 
 static void SignGeneratedShellPayload(SignatureTest signature_test,
diff --git a/extent_writer.h b/extent_writer.h
index 1744781..99b2c2f 100644
--- a/extent_writer.h
+++ b/extent_writer.h
@@ -33,7 +33,7 @@
 
 class ExtentWriter {
  public:
-  ExtentWriter() : end_called_(false) {}
+  ExtentWriter() = default;
   virtual ~ExtentWriter() {
     LOG_IF(ERROR, !end_called_) << "End() not called on ExtentWriter.";
   }
@@ -54,7 +54,7 @@
   }
   virtual bool EndImpl() = 0;
  private:
-  bool end_called_;
+  bool end_called_{false};
 };
 
 // DirectExtentWriter is probably the simplest ExtentWriter implementation.
@@ -62,35 +62,29 @@
 
 class DirectExtentWriter : public ExtentWriter {
  public:
-  DirectExtentWriter()
-      : fd_(nullptr),
-        block_size_(0),
-        extent_bytes_written_(0),
-        next_extent_index_(0) {}
-  ~DirectExtentWriter() {}
+  DirectExtentWriter() = default;
+  ~DirectExtentWriter() override = default;
 
   bool Init(FileDescriptorPtr fd,
             const std::vector<Extent>& extents,
-            uint32_t block_size) {
+            uint32_t block_size) override {
     fd_ = fd;
     block_size_ = block_size;
     extents_ = extents;
     return true;
   }
-  bool Write(const void* bytes, size_t count);
-  bool EndImpl() {
-    return true;
-  }
+  bool Write(const void* bytes, size_t count) override;
+  bool EndImpl() override { return true; }
 
  private:
-  FileDescriptorPtr fd_;
+  FileDescriptorPtr fd_{nullptr};
 
-  size_t block_size_;
+  size_t block_size_{0};
   // Bytes written into next_extent_index_ thus far
-  uint64_t extent_bytes_written_;
+  uint64_t extent_bytes_written_{0};
   std::vector<Extent> extents_;
   // The next call to write should correspond to extents_[next_extent_index_]
-  std::vector<Extent>::size_type next_extent_index_;
+  std::vector<Extent>::size_type next_extent_index_{0};
 };
 
 // Takes an underlying ExtentWriter to which all operations are delegated.
@@ -100,19 +94,18 @@
 
 class ZeroPadExtentWriter : public ExtentWriter {
  public:
-  explicit ZeroPadExtentWriter(ExtentWriter* underlying_extent_writer)
-      : underlying_extent_writer_(underlying_extent_writer),
-        block_size_(0),
-        bytes_written_mod_block_size_(0) {}
-  ~ZeroPadExtentWriter() {}
+  explicit ZeroPadExtentWriter(
+      std::unique_ptr<ExtentWriter> underlying_extent_writer)
+      : underlying_extent_writer_(std::move(underlying_extent_writer)) {}
+  ~ZeroPadExtentWriter() override = default;
 
   bool Init(FileDescriptorPtr fd,
             const std::vector<Extent>& extents,
-            uint32_t block_size) {
+            uint32_t block_size) override {
     block_size_ = block_size;
     return underlying_extent_writer_->Init(fd, extents, block_size);
   }
-  bool Write(const void* bytes, size_t count) {
+  bool Write(const void* bytes, size_t count) override {
     if (underlying_extent_writer_->Write(bytes, count)) {
       bytes_written_mod_block_size_ += count;
       bytes_written_mod_block_size_ %= block_size_;
@@ -120,7 +113,7 @@
     }
     return false;
   }
-  bool EndImpl() {
+  bool EndImpl() override {
     if (bytes_written_mod_block_size_) {
       const size_t write_size = block_size_ - bytes_written_mod_block_size_;
       chromeos::Blob zeros(write_size, 0);
@@ -131,9 +124,9 @@
   }
 
  private:
-  ExtentWriter* underlying_extent_writer_;  // The underlying ExtentWriter.
-  size_t block_size_;
-  size_t bytes_written_mod_block_size_;
+  std::unique_ptr<ExtentWriter> underlying_extent_writer_;
+  size_t block_size_{0};
+  size_t bytes_written_mod_block_size_{0};
 };
 
 }  // namespace chromeos_update_engine
diff --git a/extent_writer_unittest.cc b/extent_writer_unittest.cc
index 9da8adb..0750ebc 100644
--- a/extent_writer_unittest.cc
+++ b/extent_writer_unittest.cc
@@ -25,6 +25,7 @@
 #include <string>
 #include <vector>
 
+#include <chromeos/make_unique_ptr.h>
 #include <chromeos/secure_blob.h>
 #include <gtest/gtest.h>
 
@@ -189,8 +190,8 @@
   chromeos::Blob data(kBlockSize * 2);
   test_utils::FillWithData(&data);
 
-  DirectExtentWriter direct_writer;
-  ZeroPadExtentWriter zero_pad_writer(&direct_writer);
+  ZeroPadExtentWriter zero_pad_writer(
+      chromeos::make_unique_ptr(new DirectExtentWriter()));
 
   EXPECT_TRUE(zero_pad_writer.Init(fd_, extents, kBlockSize));
   size_t bytes_to_write = data.size();
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index d38c5c5..a600c9c 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -171,15 +171,13 @@
 }
 
 void VerifySignedPayload(const string& in_file,
-                         const string& public_key,
-                         int public_key_version) {
+                         const string& public_key) {
   LOG(INFO) << "Verifying signed payload.";
   LOG_IF(FATAL, in_file.empty())
       << "Must pass --in_file to verify signed payload.";
   LOG_IF(FATAL, public_key.empty())
       << "Must pass --public_key to verify signed payload.";
-  CHECK(PayloadVerifier::VerifySignedPayload(in_file, public_key,
-                                             public_key_version));
+  CHECK(PayloadVerifier::VerifySignedPayload(in_file, public_key));
   LOG(INFO) << "Done verifying signed payload.";
 }
 
@@ -241,9 +239,8 @@
                 "Path to output metadata hash file");
   DEFINE_string(private_key, "", "Path to private key in .pem format");
   DEFINE_string(public_key, "", "Path to public key in .pem format");
-  DEFINE_int32(public_key_version,
-               chromeos_update_engine::kSignatureMessageCurrentVersion,
-               "Key-check version # of client");
+  DEFINE_int32(public_key_version, -1,
+               "DEPRECATED. Key-check version # of client");
   DEFINE_string(prefs_dir, "/tmp/update_engine_prefs",
                 "Preferences directory, used with apply_delta");
   DEFINE_string(signature_size, "",
@@ -344,8 +341,9 @@
     return 0;
   }
   if (!FLAGS_public_key.empty()) {
-    VerifySignedPayload(FLAGS_in_file, FLAGS_public_key,
-                        FLAGS_public_key_version);
+    LOG_IF(WARNING, FLAGS_public_key_version != -1)
+        << "--public_key_version is deprecated and ignored.";
+    VerifySignedPayload(FLAGS_in_file, FLAGS_public_key);
     return 0;
   }
   if (!FLAGS_in_file.empty()) {
diff --git a/payload_generator/payload_signer.cc b/payload_generator/payload_signer.cc
index 218b432..4a2bb95 100644
--- a/payload_generator/payload_signer.cc
+++ b/payload_generator/payload_signer.cc
@@ -38,22 +38,21 @@
 
 namespace {
 
+// The payload verifier will check all the signatures included in the payload
+// regardless of the version field. Old version of the verifier require the
+// version field to be included and be 1.
+const uint32_t kSignatureMessageLegacyVersion = 1;
+
 // Given raw |signatures|, packs them into a protobuf and serializes it into a
 // binary blob. Returns true on success, false otherwise.
 bool ConvertSignatureToProtobufBlob(const vector<chromeos::Blob>& signatures,
                                     chromeos::Blob* out_signature_blob) {
   // Pack it into a protobuf
   Signatures out_message;
-  uint32_t version = kSignatureMessageOriginalVersion;
-  LOG_IF(WARNING, kSignatureMessageCurrentVersion -
-         kSignatureMessageOriginalVersion + 1 < signatures.size())
-      << "You may want to support clients in the range ["
-      << kSignatureMessageOriginalVersion << ", "
-      << kSignatureMessageCurrentVersion << "] inclusive, but you only "
-      << "provided " << signatures.size() << " signatures.";
   for (const chromeos::Blob& signature : signatures) {
     Signatures_Signature* sig_message = out_message.add_signatures();
-    sig_message->set_version(version++);
+    // Set all the signatures with the same version number.
+    sig_message->set_version(kSignatureMessageLegacyVersion);
     sig_message->set_data(signature.data(), signature.size());
   }
 
@@ -156,16 +155,10 @@
                                          padded_hash.data(),
                                          padded_hash.size()));
 
-  // This runs on the server, so it's okay to cop out and call openssl
-  // executable rather than properly use the library
-  vector<string> cmd;
-  base::SplitString("openssl rsautl -raw -sign -inkey x -in x -out x",
-                    ' ',
-                    &cmd);
-  cmd[cmd.size() - 5] = private_key_path;
-  cmd[cmd.size() - 3] = hash_path;
-  cmd[cmd.size() - 1] = sig_path;
-
+  // 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));
diff --git a/payload_generator/payload_signer_unittest.cc b/payload_generator/payload_signer_unittest.cc
index 1cd45ce..cedb432 100644
--- a/payload_generator/payload_signer_unittest.cc
+++ b/payload_generator/payload_signer_unittest.cc
@@ -94,30 +94,37 @@
 };
 
 namespace {
-void SignSampleData(chromeos::Blob* out_signature_blob) {
+void SignSampleData(chromeos::Blob* out_signature_blob,
+                    const vector<string>& private_keys) {
   string data_path;
-  ASSERT_TRUE(
-      utils::MakeTempFile("data.XXXXXX", &data_path, nullptr));
+  ASSERT_TRUE(utils::MakeTempFile("data.XXXXXX", &data_path, nullptr));
   ScopedPathUnlinker data_path_unlinker(data_path);
   ASSERT_TRUE(utils::WriteFile(data_path.c_str(),
                                kDataToSign,
                                strlen(kDataToSign)));
   uint64_t length = 0;
-  EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
-      vector<string> (1, kUnittestPrivateKeyPath),
-      &length));
+  EXPECT_TRUE(PayloadSigner::SignatureBlobLength(private_keys, &length));
   EXPECT_GT(length, 0);
   EXPECT_TRUE(PayloadSigner::SignPayload(
       data_path,
-      vector<string>(1, kUnittestPrivateKeyPath),
+      private_keys,
       out_signature_blob));
   EXPECT_EQ(length, out_signature_blob->size());
 }
 }  // namespace
 
-TEST(PayloadSignerTest, SimpleTest) {
+class PayloadSignerTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    PayloadVerifier::PadRSA2048SHA256Hash(&padded_hash_data_);
+  }
+
+  chromeos::Blob padded_hash_data_{std::begin(kDataHash), std::end(kDataHash)};
+};
+
+TEST_F(PayloadSignerTest, SignSimpleTextTest) {
   chromeos::Blob signature_blob;
-  SignSampleData(&signature_blob);
+  SignSampleData(&signature_blob, {kUnittestPrivateKeyPath});
 
   // Check the signature itself
   Signatures signatures;
@@ -125,7 +132,7 @@
                                         signature_blob.size()));
   EXPECT_EQ(1, signatures.signatures_size());
   const Signatures_Signature& signature = signatures.signatures(0);
-  EXPECT_EQ(kSignatureMessageOriginalVersion, signature.version());
+  EXPECT_EQ(1, signature.version());
   const string sig_data = signature.data();
   ASSERT_EQ(arraysize(kDataSignature), sig_data.size());
   for (size_t i = 0; i < arraysize(kDataSignature); i++) {
@@ -133,20 +140,31 @@
   }
 }
 
-TEST(PayloadSignerTest, VerifySignatureTest) {
+TEST_F(PayloadSignerTest, VerifyAllSignatureTest) {
   chromeos::Blob signature_blob;
-  SignSampleData(&signature_blob);
+  SignSampleData(&signature_blob,
+                 {kUnittestPrivateKeyPath, kUnittestPrivateKey2Path});
 
-  chromeos::Blob hash_data;
+  // Either public key should pass the verification.
   EXPECT_TRUE(PayloadVerifier::VerifySignature(signature_blob,
-                                             kUnittestPublicKeyPath,
-                                             &hash_data));
-  chromeos::Blob padded_hash_data(std::begin(kDataHash), std::end(kDataHash));
-  PayloadVerifier::PadRSA2048SHA256Hash(&padded_hash_data);
-  ASSERT_EQ(padded_hash_data.size(), hash_data.size());
-  for (size_t i = 0; i < padded_hash_data.size(); i++) {
-    EXPECT_EQ(padded_hash_data[i], hash_data[i]);
-  }
+                                               kUnittestPublicKeyPath,
+                                               padded_hash_data_));
+  EXPECT_TRUE(PayloadVerifier::VerifySignature(signature_blob,
+                                               kUnittestPublicKey2Path,
+                                               padded_hash_data_));
+}
+
+TEST_F(PayloadSignerTest, VerifySignatureTest) {
+  chromeos::Blob signature_blob;
+  SignSampleData(&signature_blob, {kUnittestPrivateKeyPath});
+
+  EXPECT_TRUE(PayloadVerifier::VerifySignature(signature_blob,
+                                               kUnittestPublicKeyPath,
+                                               padded_hash_data_));
+  // Passing the invalid key should fail the verification.
+  EXPECT_FALSE(PayloadVerifier::VerifySignature(signature_blob,
+                                                kUnittestPublicKey2Path,
+                                                padded_hash_data_));
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_verifier.cc b/payload_verifier.cc
index c3dc134..f713fb1 100644
--- a/payload_verifier.cc
+++ b/payload_verifier.cc
@@ -28,9 +28,6 @@
 
 namespace chromeos_update_engine {
 
-const uint32_t kSignatureMessageOriginalVersion = 1;
-const uint32_t kSignatureMessageCurrentVersion = 1;
-
 namespace {
 
 // The following is a standard PKCS1-v1_5 padding for SHA256 signatures, as
@@ -111,38 +108,43 @@
 
 bool PayloadVerifier::VerifySignature(const chromeos::Blob& signature_blob,
                                       const string& public_key_path,
-                                      chromeos::Blob* out_hash_data) {
-  return VerifySignatureBlob(signature_blob, public_key_path,
-                             kSignatureMessageCurrentVersion, out_hash_data);
-}
-
-bool PayloadVerifier::VerifySignatureBlob(
-    const chromeos::Blob& signature_blob,
-    const string& public_key_path,
-    uint32_t client_version,
-    chromeos::Blob* out_hash_data) {
+                                      const chromeos::Blob& hash_data) {
   TEST_AND_RETURN_FALSE(!public_key_path.empty());
 
   Signatures signatures;
-  LOG(INFO) << "signature size = " <<  signature_blob.size();
+  LOG(INFO) << "signature blob size = " <<  signature_blob.size();
   TEST_AND_RETURN_FALSE(signatures.ParseFromArray(signature_blob.data(),
                                                   signature_blob.size()));
 
-  // Finds a signature that matches the current version.
-  int sig_index = 0;
-  for (; sig_index < signatures.signatures_size(); sig_index++) {
-    const Signatures_Signature& signature = signatures.signatures(sig_index);
-    if (signature.has_version() &&
-        signature.version() == client_version) {
-      break;
-    }
+  if (!signatures.signatures_size()) {
+    LOG(ERROR) << "No signatures stored in the blob.";
+    return false;
   }
-  TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
 
-  const Signatures_Signature& signature = signatures.signatures(sig_index);
-  chromeos::Blob sig_data(signature.data().begin(), signature.data().end());
+  std::vector<chromeos::Blob> tested_hashes;
+  // Tries every signature in the signature blob.
+  for (int i = 0; i < signatures.signatures_size(); i++) {
+    const Signatures_Signature& signature = signatures.signatures(i);
+    chromeos::Blob sig_data(signature.data().begin(), signature.data().end());
+    chromeos::Blob sig_hash_data;
+    if (!GetRawHashFromSignature(sig_data, public_key_path, &sig_hash_data))
+      continue;
 
-  return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
+    if (hash_data == sig_hash_data) {
+      LOG(INFO) << "Verified correct signature " << i + 1 << " out of "
+                << signatures.signatures_size() << " signatures.";
+      return true;
+    }
+    tested_hashes.push_back(sig_hash_data);
+  }
+  LOG(ERROR) << "None of the " << signatures.signatures_size()
+             << " signatures is correct. Expected:";
+  utils::HexDumpVector(hash_data);
+  LOG(ERROR) << "But found decrypted hashes:";
+  for (const auto& sig_hash_data : tested_hashes) {
+    utils::HexDumpVector(sig_hash_data);
+  }
+  return false;
 }
 
 
@@ -191,8 +193,7 @@
 }
 
 bool PayloadVerifier::VerifySignedPayload(const string& payload_path,
-                                          const string& public_key_path,
-                                          uint32_t client_key_check_version) {
+                                          const string& public_key_path) {
   chromeos::Blob payload;
   DeltaArchiveManifest manifest;
   uint64_t metadata_size;
@@ -206,15 +207,12 @@
   chromeos::Blob signature_blob(
       payload.begin() + metadata_size + manifest.signatures_offset(),
       payload.end());
-  chromeos::Blob signed_hash;
-  TEST_AND_RETURN_FALSE(VerifySignatureBlob(
-      signature_blob, public_key_path, client_key_check_version, &signed_hash));
-  TEST_AND_RETURN_FALSE(!signed_hash.empty());
   chromeos::Blob hash;
   TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
       payload.data(), metadata_size + manifest.signatures_offset(), &hash));
-  PadRSA2048SHA256Hash(&hash);
-  TEST_AND_RETURN_FALSE(hash == signed_hash);
+  TEST_AND_RETURN_FALSE(PadRSA2048SHA256Hash(&hash));
+  TEST_AND_RETURN_FALSE(VerifySignature(
+      signature_blob, public_key_path, hash));
   return true;
 }
 
diff --git a/payload_verifier.h b/payload_verifier.h
index edaa754..faea31d 100644
--- a/payload_verifier.h
+++ b/payload_verifier.h
@@ -30,26 +30,16 @@
 
 namespace chromeos_update_engine {
 
-extern const uint32_t kSignatureMessageOriginalVersion;
-extern const uint32_t kSignatureMessageCurrentVersion;
-
 class PayloadVerifier {
  public:
-  // Returns false if the payload signature can't be verified. Returns true
-  // otherwise and sets |out_hash| to the signed payload hash.
+  // Interprets |signature_blob| as a protocol buffer containing the Signatures
+  // message and decrypts each signature data using the |public_key_path|.
+  // Returns whether *any* of the decrypted hashes matches the |hash_data|.
+  // In case of any error parsing the signatures or the public key, returns
+  // false.
   static bool VerifySignature(const chromeos::Blob& signature_blob,
                               const std::string& public_key_path,
-                              chromeos::Blob* out_hash_data);
-
-  // Interprets signature_blob as a protocol buffer containing the Signatures
-  // message and decrypts the signature data using the public_key_path and
-  // stores the resultant raw hash data in out_hash_data. Returns true if
-  // everything is successful. False otherwise. It also takes the client_version
-  // and interprets the signature blob according to that version.
-  static bool VerifySignatureBlob(const chromeos::Blob& signature_blob,
-                                  const std::string& public_key_path,
-                                  uint32_t client_version,
-                                  chromeos::Blob* out_hash_data);
+                              const chromeos::Blob& hash_data);
 
   // Decrypts sig_data with the given public_key_path and populates
   // out_hash_data with the decoded raw hash. Returns true if successful,
@@ -62,8 +52,7 @@
   // verified using the public key in |public_key_path| with the signature
   // of a given version in the signature blob. Returns false otherwise.
   static bool VerifySignedPayload(const std::string& payload_path,
-                                  const std::string& public_key_path,
-                                  uint32_t client_key_check_version);
+                                  const std::string& public_key_path);
 
   // Pads a SHA256 hash so that it may be encrypted/signed with RSA2048
   // using the PKCS#1 v1.5 scheme.