update_engine: Split payload signing and verification.
Payloads are only signed on server-side code (delta_generator) and
verified on both sides and unittest. This removes the dependency of
payload_generator/ code from delta_performer.cc by spliting the
payload signing and verification in two files.
Currently, both files are still included on all the built files.
This patch also includes some minor linter fixes.
BUG=chromium:394184
TEST=FEATURES="test" emerge-link update_engine; sudo emerge update_engine
Change-Id: Ia4268257f4260902bc37612f429f44ba7e8f65fd
Reviewed-on: https://chromium-review.googlesource.com/208540
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/delta_performer.cc b/delta_performer.cc
index 2008536..a22adfb 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -25,8 +25,8 @@
#include "update_engine/extent_writer.h"
#include "update_engine/hardware_interface.h"
#include "update_engine/payload_constants.h"
-#include "update_engine/payload_signer.h"
#include "update_engine/payload_state_interface.h"
+#include "update_engine/payload_verifier.h"
#include "update_engine/prefs_interface.h"
#include "update_engine/subprocess.h"
#include "update_engine/terminator.h"
@@ -890,9 +890,9 @@
<< path_to_public_key.value();
vector<char> expected_metadata_hash;
- if (!PayloadSigner::GetRawHashFromSignature(metadata_signature,
- path_to_public_key.value(),
- &expected_metadata_hash)) {
+ if (!PayloadVerifier::GetRawHashFromSignature(metadata_signature,
+ path_to_public_key.value(),
+ &expected_metadata_hash)) {
LOG(ERROR) << "Unable to compute expected hash from metadata signature";
return ErrorCode::kDownloadMetadataSignatureError;
}
@@ -905,7 +905,7 @@
}
vector<char> calculated_metadata_hash = metadata_hasher.raw_hash();
- PayloadSigner::PadRSA2048SHA256Hash(&calculated_metadata_hash);
+ PayloadVerifier::PadRSA2048SHA256Hash(&calculated_metadata_hash);
if (calculated_metadata_hash.empty()) {
LOG(ERROR) << "Computed actual hash of metadata is empty.";
return ErrorCode::kDownloadMetadataSignatureVerificationError;
@@ -1078,7 +1078,7 @@
!signatures_message_data_.empty());
vector<char> signed_hash_data;
TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
- PayloadSigner::VerifySignature(
+ PayloadVerifier::VerifySignature(
signatures_message_data_,
path_to_public_key.value(),
&signed_hash_data));
@@ -1088,7 +1088,7 @@
TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
signed_hasher.Finalize());
vector<char> hash_data = signed_hasher.raw_hash();
- PayloadSigner::PadRSA2048SHA256Hash(&hash_data);
+ PayloadVerifier::PadRSA2048SHA256Hash(&hash_data);
TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
!hash_data.empty());
if (hash_data != signed_hash_data) {
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index 226427f..c2e4667 100644
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -23,7 +23,8 @@
#include "update_engine/fake_system_state.h"
#include "update_engine/payload_constants.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
-#include "update_engine/payload_signer.h"
+#include "update_engine/payload_generator/payload_signer.h"
+#include "update_engine/payload_verifier.h"
#include "update_engine/prefs_mock.h"
#include "update_engine/test_utils.h"
#include "update_engine/update_metadata.pb.h"
@@ -172,7 +173,7 @@
vector<vector<char> >(1, signature),
payload_path,
out_metadata_size));
- EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
+ EXPECT_TRUE(PayloadVerifier::VerifySignedPayload(
payload_path,
kUnittestPublicKeyPath,
kSignatureMessageOriginalVersion));
@@ -222,7 +223,7 @@
// Pad the hash
vector<char> hash;
ASSERT_TRUE(utils::ReadFile(hash_file, &hash));
- ASSERT_TRUE(PayloadSigner::PadRSA2048SHA256Hash(&hash));
+ ASSERT_TRUE(PayloadVerifier::PadRSA2048SHA256Hash(&hash));
ASSERT_TRUE(WriteFileVector(hash_file, hash));
string sig_file;
@@ -521,10 +522,10 @@
// Check the metadata.
{
DeltaArchiveManifest manifest;
- EXPECT_TRUE(PayloadSigner::LoadPayload(state->delta_path,
- &state->delta,
- &manifest,
- &state->metadata_size));
+ EXPECT_TRUE(PayloadVerifier::LoadPayload(state->delta_path,
+ &state->delta,
+ &manifest,
+ &state->metadata_size));
LOG(INFO) << "Metadata size: " << state->metadata_size;
diff --git a/payload_generator/delta_diff_generator.cc b/payload_generator/delta_diff_generator.cc
index 587892c..1367b17 100644
--- a/payload_generator/delta_diff_generator.cc
+++ b/payload_generator/delta_diff_generator.cc
@@ -39,8 +39,9 @@
#include "update_engine/payload_generator/graph_types.h"
#include "update_engine/payload_generator/graph_utils.h"
#include "update_engine/payload_generator/metadata.h"
+#include "update_engine/payload_generator/payload_signer.h"
#include "update_engine/payload_generator/topological_sort.h"
-#include "update_engine/payload_signer.h"
+#include "update_engine/payload_verifier.h"
#include "update_engine/subprocess.h"
#include "update_engine/update_metadata.pb.h"
#include "update_engine/utils.h"
@@ -60,7 +61,7 @@
const uint64_t kFullUpdateChunkSize = 1024 * 1024; // bytes
const size_t kBlockSize = 4096; // bytes
-const string kNonexistentPath = "";
+const char kEmptyPath[] = "";
static const char* kInstallOperationTypes[] = {
"REPLACE",
@@ -81,7 +82,7 @@
const size_t kRootFSPartitionSize = static_cast<size_t>(2) * 1024 * 1024 * 1024;
// Needed for testing purposes, in case we can't use actual filesystem objects.
-// TODO(garnold)(chromium:331965) Replace this hack with a properly injected
+// TODO(garnold) (chromium:331965) Replace this hack with a properly injected
// parameter in form of a mockable abstract class.
bool (*get_extents_with_chunk_func)(const std::string&, off_t, off_t,
std::vector<Extent>*) =
@@ -122,7 +123,7 @@
vector<char> data;
DeltaArchiveManifest_InstallOperation operation;
- string old_path = (old_root == kNonexistentPath) ? kNonexistentPath :
+ string old_path = (old_root == kEmptyPath) ? kEmptyPath :
old_root + path;
// If bsdiff breaks again, blacklist the problem file by using:
@@ -243,7 +244,7 @@
blocks,
(should_diff_from_source ?
old_root :
- kNonexistentPath),
+ kEmptyPath),
new_root,
fs_iter.GetPartialPath(),
offset,
@@ -470,7 +471,7 @@
new_kernel_part,
0, // chunk_offset
-1, // chunk_size
- true, // bsdiff_allowed
+ true, // bsdiff_allowed
&data,
&op,
false));
@@ -1038,19 +1039,20 @@
class SortCutsByTopoOrderLess {
public:
- SortCutsByTopoOrderLess(vector<vector<Vertex::Index>::size_type>& table)
+ explicit SortCutsByTopoOrderLess(
+ const vector<vector<Vertex::Index>::size_type>& table)
: table_(table) {}
bool operator()(const CutEdgeVertexes& a, const CutEdgeVertexes& b) {
return table_[a.old_dst] < table_[b.old_dst];
}
private:
- vector<vector<Vertex::Index>::size_type>& table_;
+ const vector<vector<Vertex::Index>::size_type>& table_;
};
} // namespace
void DeltaDiffGenerator::GenerateReverseTopoOrderMap(
- vector<Vertex::Index>& op_indexes,
+ const vector<Vertex::Index>& op_indexes,
vector<vector<Vertex::Index>::size_type>* reverse_op_indexes) {
vector<vector<Vertex::Index>::size_type> table(op_indexes.size());
for (vector<Vertex::Index>::size_type i = 0, e = op_indexes.size();
@@ -1064,8 +1066,9 @@
reverse_op_indexes->swap(table);
}
-void DeltaDiffGenerator::SortCutsByTopoOrder(vector<Vertex::Index>& op_indexes,
- vector<CutEdgeVertexes>* cuts) {
+void DeltaDiffGenerator::SortCutsByTopoOrder(
+ const vector<Vertex::Index>& op_indexes,
+ vector<CutEdgeVertexes>* cuts) {
// first, make a reverse lookup table.
vector<vector<Vertex::Index>::size_type> table;
GenerateReverseTopoOrderMap(op_indexes, &table);
@@ -1438,7 +1441,7 @@
TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
cut.old_dst,
NULL,
- kNonexistentPath,
+ kEmptyPath,
new_root,
(*graph)[cut.old_dst].file_name,
(*graph)[cut.old_dst].chunk_offset,
@@ -1563,7 +1566,7 @@
<< "Old and new images have different block counts.";
// If new_image_info is present, old_image_info must be present.
- TEST_AND_RETURN_FALSE((bool)old_image_info == (bool)new_image_info);
+ TEST_AND_RETURN_FALSE(!old_image_info == !new_image_info);
} else {
// old_image_info must not be present for a full update.
TEST_AND_RETURN_FALSE(!old_image_info);
diff --git a/payload_generator/delta_diff_generator.h b/payload_generator/delta_diff_generator.h
index 596d9c0..3c4ad69 100644
--- a/payload_generator/delta_diff_generator.h
+++ b/payload_generator/delta_diff_generator.h
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
-#define CHROMEOS_PLATFORM_UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
+#ifndef UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
+#define UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
+#include <set>
#include <string>
#include <vector>
@@ -167,8 +168,9 @@
// Sorts the vector |cuts| by its |cuts[].old_dest| member. Order is
// determined by the order of elements in op_indexes.
- static void SortCutsByTopoOrder(std::vector<Vertex::Index>& op_indexes,
- std::vector<CutEdgeVertexes>* cuts);
+ static void SortCutsByTopoOrder(
+ const std::vector<Vertex::Index>& op_indexes,
+ std::vector<CutEdgeVertexes>* cuts);
// Returns true iff there are no extents in the graph that refer to temp
// blocks. Temp blocks are in the range [kTempBlockStart, kSparseHole).
@@ -211,7 +213,7 @@
// which the op is performed -> graph vertex index, and produces the
// reverse: a mapping from graph vertex index -> op_indexes index.
static void GenerateReverseTopoOrderMap(
- std::vector<Vertex::Index>& op_indexes,
+ const std::vector<Vertex::Index>& op_indexes,
std::vector<std::vector<Vertex::Index>::size_type>* reverse_op_indexes);
// Takes a |graph|, which has edges that must be cut, as listed in
@@ -264,7 +266,7 @@
DeltaArchiveManifest* manifest);
private:
- // This should never be constructed
+ // This should never be constructed.
DISALLOW_IMPLICIT_CONSTRUCTORS(DeltaDiffGenerator);
};
@@ -273,4 +275,4 @@
}; // namespace chromeos_update_engine
-#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
+#endif // UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
diff --git a/payload_generator/delta_diff_generator_unittest.cc b/payload_generator/delta_diff_generator_unittest.cc
index c9ac8cf..977b34d 100644
--- a/payload_generator/delta_diff_generator_unittest.cc
+++ b/payload_generator/delta_diff_generator_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "update_engine/payload_generator/delta_diff_generator.h"
+
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -22,7 +24,6 @@
#include "update_engine/extent_ranges.h"
#include "update_engine/payload_constants.h"
#include "update_engine/payload_generator/cycle_breaker.h"
-#include "update_engine/payload_generator/delta_diff_generator.h"
#include "update_engine/payload_generator/extent_mapper.h"
#include "update_engine/payload_generator/graph_types.h"
#include "update_engine/payload_generator/graph_utils.h"
@@ -91,7 +92,7 @@
new_path(),
0, // chunk_offset
-1, // chunk_size
- true, // bsdiff_allowed
+ true, // bsdiff_allowed
&data,
&op,
true));
@@ -181,7 +182,7 @@
new_path(),
0, // chunk_offset
-1, // chunk_size
- true, // bsdiff_allowed
+ true, // bsdiff_allowed
&data,
&op,
true));
@@ -245,7 +246,7 @@
new_path(),
0, // chunk_offset
-1, // chunk_size
- true, // bsdiff_allowed
+ true, // bsdiff_allowed
&data,
&op,
true));
@@ -278,7 +279,7 @@
new_path(),
0, // chunk_offset
-1, // chunk_size
- false, // bsdiff_allowed
+ false, // bsdiff_allowed
&data,
&op,
true));
@@ -304,7 +305,7 @@
new_path(),
0, // chunk_offset
-1, // chunk_size
- false, // bsdiff_allowed
+ false, // bsdiff_allowed
&data,
&op,
true));
@@ -331,7 +332,7 @@
new_path(),
0, // chunk_offset
-1, // chunk_size
- true, // bsdiff_allowed
+ true, // bsdiff_allowed
&data,
&op,
true));
@@ -365,7 +366,7 @@
new_path(),
0, // chunk_offset
-1, // chunk_size
- true, // bsdiff_allowed
+ true, // bsdiff_allowed
&data,
&op,
false));
@@ -398,7 +399,7 @@
extent->set_start_block(start);
extent->set_num_blocks(length);
}
-}
+} // namespace
TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) {
vector<Extent> remove_blocks;
@@ -498,8 +499,8 @@
cycle_breaker.BreakCycles(graph, &cut_edges);
EXPECT_EQ(1, cut_edges.size());
- EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1,
- 0)));
+ EXPECT_TRUE(cut_edges.end() != cut_edges.find(
+ std::pair<Vertex::Index, Vertex::Index>(1, 0)));
vector<CutEdgeVertexes> cuts;
EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts));
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index 89bb2b9..a2b6b3c 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -21,7 +21,8 @@
#include "update_engine/delta_performer.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
-#include "update_engine/payload_signer.h"
+#include "update_engine/payload_generator/payload_signer.h"
+#include "update_engine/payload_verifier.h"
#include "update_engine/prefs.h"
#include "update_engine/subprocess.h"
#include "update_engine/terminator.h"
@@ -142,7 +143,6 @@
const string& build_channel,
const string& build_version,
ImageInfo* image_info) {
-
// All of these arguments should be present or missing.
bool empty = channel.empty();
@@ -237,8 +237,8 @@
<< "Must pass --in_file to verify signed payload.";
LOG_IF(FATAL, FLAGS_public_key.empty())
<< "Must pass --public_key to verify signed payload.";
- CHECK(PayloadSigner::VerifySignedPayload(FLAGS_in_file, FLAGS_public_key,
- FLAGS_public_key_version));
+ CHECK(PayloadVerifier::VerifySignedPayload(FLAGS_in_file, FLAGS_public_key,
+ FLAGS_public_key_version));
LOG(INFO) << "Done verifying signed payload.";
}
diff --git a/payload_signer.cc b/payload_generator/payload_signer.cc
similarity index 63%
rename from payload_signer.cc
rename to payload_generator/payload_signer.cc
index 3d09737..4bbb155 100644
--- a/payload_signer.cc
+++ b/payload_generator/payload_signer.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "update_engine/payload_signer.h"
+#include "update_engine/payload_generator/payload_signer.h"
#include <base/logging.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <openssl/pem.h>
-#include "update_engine/delta_performer.h"
#include "update_engine/omaha_hash_calculator.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_verifier.h"
#include "update_engine/subprocess.h"
#include "update_engine/update_metadata.pb.h"
#include "update_engine/utils.h"
@@ -21,64 +21,8 @@
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
-// defined in RFC3447. It is prepended to the actual signature (32 bytes) to
-// form a sequence of 256 bytes (2048 bits) that is amenable to RSA signing. The
-// padded hash will look as follows:
-//
-// 0x00 0x01 0xff ... 0xff 0x00 ASN1HEADER SHA256HASH
-// |--------------205-----------||----19----||----32----|
-//
-// where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
-// bytes of actual data (i.e. the ASN.1 header complete with the hash) are
-// packed as follows:
-//
-// SEQUENCE(2+49) {
-// SEQUENCE(2+13) {
-// OBJECT(2+9) id-sha256
-// NULL(2+0)
-// }
-// OCTET STRING(2+32) <actual signature bytes...>
-// }
-const unsigned char kRSA2048SHA256Padding[] = {
- // PKCS1-v1_5 padding
- 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00,
- // ASN.1 header
- 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
- 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
- 0x00, 0x04, 0x20,
-};
-
// 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<vector<char> >& signatures,
@@ -128,7 +72,7 @@
vector<char> payload;
DeltaArchiveManifest manifest;
uint64_t metadata_size;
- TEST_AND_RETURN_FALSE(PayloadSigner::LoadPayload(
+ TEST_AND_RETURN_FALSE(PayloadVerifier::LoadPayload(
payload_path, &payload, &manifest, &metadata_size));
// Is there already a signature op in place?
@@ -178,27 +122,6 @@
}
} // namespace
-bool PayloadSigner::LoadPayload(const string& payload_path,
- vector<char>* out_payload,
- DeltaArchiveManifest* out_manifest,
- uint64_t* out_metadata_size) {
- vector<char> payload;
- // Loads the payload and parses the manifest.
- TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
- LOG(INFO) << "Payload size: " << payload.size();
- ErrorCode error = ErrorCode::kSuccess;
- InstallPlan install_plan;
- DeltaPerformer delta_performer(NULL, NULL, &install_plan);
- TEST_AND_RETURN_FALSE(
- delta_performer.ParsePayloadMetadata(payload, &error) ==
- DeltaPerformer::kMetadataParseSuccess);
- TEST_AND_RETURN_FALSE(delta_performer.GetManifest(out_manifest));
- *out_metadata_size = delta_performer.GetMetadataSize();
- LOG(INFO) << "Metadata size: " << *out_metadata_size;
- out_payload->swap(payload);
- return true;
-}
-
bool PayloadSigner::SignHash(const vector<char>& hash,
const string& private_key_path,
vector<char>* out_signature) {
@@ -215,7 +138,7 @@
// We expect unpadded SHA256 hash coming in
TEST_AND_RETURN_FALSE(hash.size() == 32);
vector<char> padded_hash(hash);
- PadRSA2048SHA256Hash(&padded_hash);
+ PayloadVerifier::PadRSA2048SHA256Hash(&padded_hash);
TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
padded_hash.data(),
padded_hash.size()));
@@ -282,116 +205,6 @@
return true;
}
-bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
- const std::string& public_key_path,
- std::vector<char>* out_hash_data) {
- return VerifySignatureBlob(signature_blob, public_key_path,
- kSignatureMessageCurrentVersion, out_hash_data);
-}
-
-bool PayloadSigner::VerifySignatureBlob(
- const std::vector<char>& signature_blob,
- const std::string& public_key_path,
- uint32_t client_version,
- std::vector<char>* out_hash_data) {
- TEST_AND_RETURN_FALSE(!public_key_path.empty());
-
- Signatures signatures;
- LOG(INFO) << "signature size = " << signature_blob.size();
- TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
- 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;
- }
- }
- TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
-
- const Signatures_Signature& signature = signatures.signatures(sig_index);
- vector<char> sig_data(signature.data().begin(), signature.data().end());
-
- return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
-}
-
-
-bool PayloadSigner::GetRawHashFromSignature(
- const std::vector<char>& sig_data,
- const std::string& public_key_path,
- std::vector<char>* out_hash_data) {
- TEST_AND_RETURN_FALSE(!public_key_path.empty());
-
- // The code below executes the equivalent of:
- //
- // openssl rsautl -verify -pubin -inkey |public_key_path|
- // -in |sig_data| -out |out_hash_data|
-
- // Loads the public key.
- FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
- if (!fpubkey) {
- LOG(ERROR) << "Unable to open public key file: " << public_key_path;
- return false;
- }
-
- char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
- RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
- fclose(fpubkey);
- TEST_AND_RETURN_FALSE(rsa != NULL);
- unsigned int keysize = RSA_size(rsa);
- if (sig_data.size() > 2 * keysize) {
- LOG(ERROR) << "Signature size is too big for public key size.";
- RSA_free(rsa);
- return false;
- }
-
- // Decrypts the signature.
- vector<char> hash_data(keysize);
- int decrypt_size = RSA_public_decrypt(
- sig_data.size(),
- reinterpret_cast<const unsigned char*>(sig_data.data()),
- reinterpret_cast<unsigned char*>(hash_data.data()),
- rsa,
- RSA_NO_PADDING);
- RSA_free(rsa);
- TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
- decrypt_size <= static_cast<int>(hash_data.size()));
- hash_data.resize(decrypt_size);
- out_hash_data->swap(hash_data);
- return true;
-}
-
-bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
- const std::string& public_key_path,
- uint32_t client_key_check_version) {
- vector<char> payload;
- DeltaArchiveManifest manifest;
- uint64_t metadata_size;
- TEST_AND_RETURN_FALSE(LoadPayload(
- payload_path, &payload, &manifest, &metadata_size));
- TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
- manifest.has_signatures_size());
- CHECK_EQ(payload.size(),
- metadata_size + manifest.signatures_offset() +
- manifest.signatures_size());
- vector<char> signature_blob(
- payload.begin() + metadata_size + manifest.signatures_offset(),
- payload.end());
- vector<char> 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());
- vector<char> hash;
- TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
- payload.data(), metadata_size + manifest.signatures_offset(), &hash));
- PadRSA2048SHA256Hash(&hash);
- TEST_AND_RETURN_FALSE(hash == signed_hash);
- return true;
-}
-
bool PayloadSigner::PrepPayloadForHashing(
const string& payload_path,
const vector<int>& signature_sizes,
@@ -492,16 +305,6 @@
return true;
}
-bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
- TEST_AND_RETURN_FALSE(hash->size() == 32);
- hash->insert(hash->begin(),
- reinterpret_cast<const char*>(kRSA2048SHA256Padding),
- reinterpret_cast<const char*>(kRSA2048SHA256Padding +
- sizeof(kRSA2048SHA256Padding)));
- TEST_AND_RETURN_FALSE(hash->size() == 256);
- return true;
-}
-
bool PayloadSigner::GetMetadataSignature(const char* const metadata,
size_t metadata_size,
const string& private_key_path,
diff --git a/payload_signer.h b/payload_generator/payload_signer.h
similarity index 61%
rename from payload_signer.h
rename to payload_generator/payload_signer.h
index d4215f5..0c540e6 100644
--- a/payload_signer.h
+++ b/payload_generator/payload_signer.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UPDATE_ENGINE_PAYLOAD_SIGNER_H_
-#define UPDATE_ENGINE_PAYLOAD_SIGNER_H_
+#ifndef UPDATE_ENGINE_PAYLOAD_GENERATOR_PAYLOAD_SIGNER_H_
+#define UPDATE_ENGINE_PAYLOAD_GENERATOR_PAYLOAD_SIGNER_H_
#include <string>
#include <vector>
@@ -11,14 +11,11 @@
#include <base/basictypes.h>
#include "update_engine/update_metadata.pb.h"
-// This class encapsulates methods used for payload signing and signature
-// verification. See update_metadata.proto for more info.
+// This class encapsulates methods used for payload signing.
+// See update_metadata.proto for more info.
namespace chromeos_update_engine {
-extern const uint32_t kSignatureMessageOriginalVersion;
-extern const uint32_t kSignatureMessageCurrentVersion;
-
class PayloadSigner {
public:
// Given a raw |hash| and a private key in |private_key_path| calculates the
@@ -92,43 +89,6 @@
const std::string& signed_payload_path,
uint64_t* out_metadata_size);
- // Returns false if the payload signature can't be verified. Returns true
- // otherwise and sets |out_hash| to the signed payload hash.
- static bool VerifySignature(const std::vector<char>& signature_blob,
- const std::string& public_key_path,
- std::vector<char>* 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 std::vector<char>& signature_blob,
- const std::string& public_key_path,
- uint32_t client_version,
- std::vector<char>* out_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,
- // false otherwise.
- static bool GetRawHashFromSignature(const std::vector<char>& sig_data,
- const std::string& public_key_path,
- std::vector<char>* out_hash_data);
-
- // Returns true if the payload in |payload_path| is signed and its hash can be
- // 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);
-
- // Pads a SHA256 hash so that it may be encrypted/signed with RSA2048
- // using the PKCS#1 v1.5 scheme.
- // hash should be a pointer to vector of exactly 256 bits. The vector
- // will be modified in place and will result in having a length of
- // 2048 bits. Returns true on success, false otherwise.
- static bool PadRSA2048SHA256Hash(std::vector<char>* hash);
-
// Computes the SHA256 hash of the first metadata_size bytes of |metadata|
// and signs the hash with the given private_key_path and writes the signed
// hash in |out_signature|. Returns true if successful or false if there was
@@ -138,15 +98,6 @@
const std::string& private_key_path,
std::string* out_signature);
- // Reads the payload from the given |payload_path| into the |out_payload|
- // vector. It also parses the manifest protobuf in the payload and returns it
- // in |out_manifest| along with the size of the entire metadata in
- // |out_metadata_size|.
- static bool LoadPayload(const std::string& payload_path,
- std::vector<char>* out_payload,
- DeltaArchiveManifest* out_manifest,
- uint64_t* out_metadata_size);
-
private:
// This should never be constructed
DISALLOW_IMPLICIT_CONSTRUCTORS(PayloadSigner);
@@ -154,4 +105,4 @@
} // namespace chromeos_update_engine
-#endif // UPDATE_ENGINE_PAYLOAD_SIGNER_H_
+#endif // UPDATE_ENGINE_PAYLOAD_GENERATOR_PAYLOAD_SIGNER_H_
diff --git a/payload_signer_unittest.cc b/payload_generator/payload_signer_unittest.cc
similarity index 95%
rename from payload_signer_unittest.cc
rename to payload_generator/payload_signer_unittest.cc
index 829fdd8..00df88c 100644
--- a/payload_signer_unittest.cc
+++ b/payload_generator/payload_signer_unittest.cc
@@ -2,11 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "update_engine/payload_generator/payload_signer.h"
+
#include <string>
#include <vector>
+
+#include <base/logging.h>
#include <gtest/gtest.h>
-#include "base/logging.h"
-#include "update_engine/payload_signer.h"
+
+#include "update_engine/payload_verifier.h"
#include "update_engine/update_metadata.pb.h"
#include "update_engine/utils.h"
@@ -122,13 +126,13 @@
SignSampleData(&signature_blob);
vector<char> hash_data;
- EXPECT_TRUE(PayloadSigner::VerifySignature(signature_blob,
+ EXPECT_TRUE(PayloadVerifier::VerifySignature(signature_blob,
kUnittestPublicKeyPath,
&hash_data));
vector<char> padded_hash_data(reinterpret_cast<const char *>(kDataHash),
reinterpret_cast<const char *>(kDataHash +
sizeof(kDataHash)));
- PayloadSigner::PadRSA2048SHA256Hash(&padded_hash_data);
+ 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]);
diff --git a/payload_verifier.cc b/payload_verifier.cc
new file mode 100644
index 0000000..fa23d4f
--- /dev/null
+++ b/payload_verifier.cc
@@ -0,0 +1,222 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/payload_verifier.h"
+
+#include <base/logging.h>
+#include <openssl/pem.h>
+
+#include "update_engine/delta_performer.h"
+#include "update_engine/omaha_hash_calculator.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/update_metadata.pb.h"
+#include "update_engine/utils.h"
+
+using std::string;
+using std::vector;
+
+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
+// defined in RFC3447. It is prepended to the actual signature (32 bytes) to
+// form a sequence of 256 bytes (2048 bits) that is amenable to RSA signing. The
+// padded hash will look as follows:
+//
+// 0x00 0x01 0xff ... 0xff 0x00 ASN1HEADER SHA256HASH
+// |--------------205-----------||----19----||----32----|
+//
+// where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
+// bytes of actual data (i.e. the ASN.1 header complete with the hash) are
+// packed as follows:
+//
+// SEQUENCE(2+49) {
+// SEQUENCE(2+13) {
+// OBJECT(2+9) id-sha256
+// NULL(2+0)
+// }
+// OCTET STRING(2+32) <actual signature bytes...>
+// }
+const unsigned char kRSA2048SHA256Padding[] = {
+ // PKCS1-v1_5 padding
+ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00,
+ // ASN.1 header
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20,
+};
+
+} // namespace
+
+bool PayloadVerifier::LoadPayload(const string& payload_path,
+ vector<char>* out_payload,
+ DeltaArchiveManifest* out_manifest,
+ uint64_t* out_metadata_size) {
+ vector<char> payload;
+ // Loads the payload and parses the manifest.
+ TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
+ LOG(INFO) << "Payload size: " << payload.size();
+ ErrorCode error = ErrorCode::kSuccess;
+ InstallPlan install_plan;
+ DeltaPerformer delta_performer(NULL, NULL, &install_plan);
+ TEST_AND_RETURN_FALSE(
+ delta_performer.ParsePayloadMetadata(payload, &error) ==
+ DeltaPerformer::kMetadataParseSuccess);
+ TEST_AND_RETURN_FALSE(delta_performer.GetManifest(out_manifest));
+ *out_metadata_size = delta_performer.GetMetadataSize();
+ LOG(INFO) << "Metadata size: " << *out_metadata_size;
+ out_payload->swap(payload);
+ return true;
+}
+
+bool PayloadVerifier::VerifySignature(const std::vector<char>& signature_blob,
+ const std::string& public_key_path,
+ std::vector<char>* out_hash_data) {
+ return VerifySignatureBlob(signature_blob, public_key_path,
+ kSignatureMessageCurrentVersion, out_hash_data);
+}
+
+bool PayloadVerifier::VerifySignatureBlob(
+ const std::vector<char>& signature_blob,
+ const std::string& public_key_path,
+ uint32_t client_version,
+ std::vector<char>* out_hash_data) {
+ TEST_AND_RETURN_FALSE(!public_key_path.empty());
+
+ Signatures signatures;
+ LOG(INFO) << "signature size = " << signature_blob.size();
+ TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
+ 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;
+ }
+ }
+ TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
+
+ const Signatures_Signature& signature = signatures.signatures(sig_index);
+ vector<char> sig_data(signature.data().begin(), signature.data().end());
+
+ return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
+}
+
+
+bool PayloadVerifier::GetRawHashFromSignature(
+ const std::vector<char>& sig_data,
+ const std::string& public_key_path,
+ std::vector<char>* out_hash_data) {
+ TEST_AND_RETURN_FALSE(!public_key_path.empty());
+
+ // The code below executes the equivalent of:
+ //
+ // openssl rsautl -verify -pubin -inkey |public_key_path|
+ // -in |sig_data| -out |out_hash_data|
+
+ // Loads the public key.
+ FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
+ if (!fpubkey) {
+ LOG(ERROR) << "Unable to open public key file: " << public_key_path;
+ return false;
+ }
+
+ char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
+ RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
+ fclose(fpubkey);
+ TEST_AND_RETURN_FALSE(rsa != NULL);
+ unsigned int keysize = RSA_size(rsa);
+ if (sig_data.size() > 2 * keysize) {
+ LOG(ERROR) << "Signature size is too big for public key size.";
+ RSA_free(rsa);
+ return false;
+ }
+
+ // Decrypts the signature.
+ vector<char> hash_data(keysize);
+ int decrypt_size = RSA_public_decrypt(
+ sig_data.size(),
+ reinterpret_cast<const unsigned char*>(sig_data.data()),
+ reinterpret_cast<unsigned char*>(hash_data.data()),
+ rsa,
+ RSA_NO_PADDING);
+ RSA_free(rsa);
+ TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
+ decrypt_size <= static_cast<int>(hash_data.size()));
+ hash_data.resize(decrypt_size);
+ out_hash_data->swap(hash_data);
+ return true;
+}
+
+bool PayloadVerifier::VerifySignedPayload(const std::string& payload_path,
+ const std::string& public_key_path,
+ uint32_t client_key_check_version) {
+ vector<char> payload;
+ DeltaArchiveManifest manifest;
+ uint64_t metadata_size;
+ TEST_AND_RETURN_FALSE(LoadPayload(
+ payload_path, &payload, &manifest, &metadata_size));
+ TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
+ manifest.has_signatures_size());
+ CHECK_EQ(payload.size(),
+ metadata_size + manifest.signatures_offset() +
+ manifest.signatures_size());
+ vector<char> signature_blob(
+ payload.begin() + metadata_size + manifest.signatures_offset(),
+ payload.end());
+ vector<char> 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());
+ vector<char> hash;
+ TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
+ payload.data(), metadata_size + manifest.signatures_offset(), &hash));
+ PadRSA2048SHA256Hash(&hash);
+ TEST_AND_RETURN_FALSE(hash == signed_hash);
+ return true;
+}
+
+bool PayloadVerifier::PadRSA2048SHA256Hash(std::vector<char>* hash) {
+ TEST_AND_RETURN_FALSE(hash->size() == 32);
+ hash->insert(hash->begin(),
+ reinterpret_cast<const char*>(kRSA2048SHA256Padding),
+ reinterpret_cast<const char*>(kRSA2048SHA256Padding +
+ sizeof(kRSA2048SHA256Padding)));
+ TEST_AND_RETURN_FALSE(hash->size() == 256);
+ return true;
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_verifier.h b/payload_verifier.h
new file mode 100644
index 0000000..ba392c9
--- /dev/null
+++ b/payload_verifier.h
@@ -0,0 +1,77 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UPDATE_ENGINE_PAYLOAD_VERIFIER_H_
+#define UPDATE_ENGINE_PAYLOAD_VERIFIER_H_
+
+#include <string>
+#include <vector>
+
+#include <base/basictypes.h>
+#include "update_engine/update_metadata.pb.h"
+
+// This class encapsulates methods used for payload signature verification.
+// See payload_generator/payload_signer.h for payload signing.
+
+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.
+ static bool VerifySignature(const std::vector<char>& signature_blob,
+ const std::string& public_key_path,
+ std::vector<char>* 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 std::vector<char>& signature_blob,
+ const std::string& public_key_path,
+ uint32_t client_version,
+ std::vector<char>* out_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,
+ // false otherwise.
+ static bool GetRawHashFromSignature(const std::vector<char>& sig_data,
+ const std::string& public_key_path,
+ std::vector<char>* out_hash_data);
+
+ // Returns true if the payload in |payload_path| is signed and its hash can be
+ // 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);
+
+ // Pads a SHA256 hash so that it may be encrypted/signed with RSA2048
+ // using the PKCS#1 v1.5 scheme.
+ // hash should be a pointer to vector of exactly 256 bits. The vector
+ // will be modified in place and will result in having a length of
+ // 2048 bits. Returns true on success, false otherwise.
+ static bool PadRSA2048SHA256Hash(std::vector<char>* hash);
+
+ // Reads the payload from the given |payload_path| into the |out_payload|
+ // vector. It also parses the manifest protobuf in the payload and returns it
+ // in |out_manifest| along with the size of the entire metadata in
+ // |out_metadata_size|.
+ static bool LoadPayload(const std::string& payload_path,
+ std::vector<char>* out_payload,
+ DeltaArchiveManifest* out_manifest,
+ uint64_t* out_metadata_size);
+
+ private:
+ // This should never be constructed
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PayloadVerifier);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_PAYLOAD_VERIFIER_H_
diff --git a/update_engine.gyp b/update_engine.gyp
index 24a9a98..c201b65 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -164,10 +164,11 @@
'payload_generator/full_update_generator.cc',
'payload_generator/graph_utils.cc',
'payload_generator/metadata.cc',
+ 'payload_generator/payload_signer.cc',
'payload_generator/tarjan.cc',
'payload_generator/topological_sort.cc',
- 'payload_signer.cc',
'payload_state.cc',
+ 'payload_verifier.cc',
'postinstall_runner_action.cc',
'prefs.cc',
'proxy_resolver.cc',
@@ -293,9 +294,9 @@
'payload_generator/full_update_generator_unittest.cc',
'payload_generator/graph_utils_unittest.cc',
'payload_generator/metadata_unittest.cc',
+ 'payload_generator/payload_signer_unittest.cc',
'payload_generator/tarjan_unittest.cc',
'payload_generator/topological_sort_unittest.cc',
- 'payload_signer_unittest.cc',
'payload_state_unittest.cc',
'postinstall_runner_action_unittest.cc',
'prefs_unittest.cc',