AU: Sign delta payloads

- Change .proto to have explicit offset/length of signature. I was
  hoping the length could be kept out of the proto, but it needs to go
  in. The way we cheat and keep the signature in the file is to have a
  dummer install operation at the end that will cause old clients to
  write the signature data to nowhere.

- Change delta generator to take an optional private key, which if
  present will cause the payload to be signed

- Cleanup Omaha hash calculator, which should be renamed to SHA1 hash
  calculator, and allow export of the non-base64 encoded SHA1 result.

- Note: signatures are not yet checked. That will come in a future CL.

BUG=5662
TEST=unittests

Review URL: http://codereview.chromium.org/3132033
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
index 48730a8..10f6846 100644
--- a/delta_diff_generator.cc
+++ b/delta_diff_generator.cc
@@ -21,6 +21,7 @@
 #include "update_engine/filesystem_iterator.h"
 #include "update_engine/graph_types.h"
 #include "update_engine/graph_utils.h"
+#include "update_engine/payload_signer.h"
 #include "update_engine/subprocess.h"
 #include "update_engine/topological_sort.h"
 #include "update_engine/update_metadata.pb.h"
@@ -92,7 +93,7 @@
             << graph[vertex].file_name;
   // See if this is already present.
   TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0);
-  
+
   enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT };
   for (int field = READER; field < BLOCK_FIELD_COUNT; field++) {
     const int extents_size =
@@ -158,13 +159,13 @@
 
   TEST_AND_RETURN_FALSE(utils::WriteAll(data_fd, &data[0], data.size()));
   *data_file_size += data.size();
-  
+
   // Now, insert into graph and blocks vector
   graph->resize(graph->size() + 1);
   graph->back().op = operation;
   CHECK(graph->back().op.has_type());
   graph->back().file_name = path;
-  
+
   TEST_AND_RETURN_FALSE(AddInstallOpToBlocksVector(graph->back().op,
                                                    blocks,
                                                    *graph,
@@ -196,7 +197,7 @@
       continue;
 
     LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath();
-    
+
     TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
                                         blocks,
                                         old_root,
@@ -298,17 +299,17 @@
   FILE* file = fopen(temp_file_path.c_str(), "w");
   TEST_AND_RETURN_FALSE(file);
   int err = BZ_OK;
-  
+
   BZFILE* bz_file = BZ2_bzWriteOpen(&err,
                                     file,
                                     9,  // max compression
                                     0,  // verbosity
                                     0);  // default work factor
   TEST_AND_RETURN_FALSE(err == BZ_OK);
-  
+
   vector<Extent> extents;
   vector<Block>::size_type block_count = 0;
-  
+
   LOG(INFO) << "Appending left over blocks to extents";
   for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
     if (blocks[i].writer != Vertex::kInvalidIndex)
@@ -356,12 +357,12 @@
   bz_file = NULL;
   TEST_AND_RETURN_FALSE_ERRNO(0 == fclose(file));
   file = NULL;
-  
+
   vector<char> compressed_data;
   LOG(INFO) << "Reading compressed data off disk";
   TEST_AND_RETURN_FALSE(utils::ReadFile(temp_file_path, &compressed_data));
   TEST_AND_RETURN_FALSE(unlink(temp_file_path.c_str()) == 0);
-  
+
   // Add node to graph to write these blocks
   out_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
   out_op->set_data_offset(*blobs_length);
@@ -369,7 +370,7 @@
   *blobs_length += compressed_data.size();
   out_op->set_dst_length(kBlockSize * block_count);
   DeltaDiffGenerator::StoreExtents(extents, out_op->mutable_dst_extents());
-  
+
   TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd,
                                         &compressed_data[0],
                                         compressed_data.size()));
@@ -414,7 +415,7 @@
 }
 
 // Delta compresses a kernel partition new_kernel_part with knowledge of
-// the old kernel partition old_kernel_part. 
+// the old kernel partition old_kernel_part.
 bool DeltaCompressKernelPartition(
     const string& old_kernel_part,
     const string& new_kernel_part,
@@ -438,12 +439,12 @@
   TEST_AND_RETURN_FALSE(BsdiffFiles(old_kernel_part, new_kernel_part, &data));
   TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd, &data[0], data.size()));
   *blobs_length += data.size();
-  
+
   off_t old_part_size = utils::FileSize(old_kernel_part);
   TEST_AND_RETURN_FALSE(old_part_size >= 0);
   off_t new_part_size = utils::FileSize(new_kernel_part);
   TEST_AND_RETURN_FALSE(new_part_size >= 0);
-  
+
   op->set_data_length(data.size());
 
   op->set_src_length(old_part_size);
@@ -457,7 +458,7 @@
   Extent* dst_extent = op->add_dst_extents();
   dst_extent->set_start_block(0);
   dst_extent->set_num_blocks((new_part_size + kBlockSize - 1) / kBlockSize);
-  
+
   LOG(INFO) << "Done delta compressing kernel partition.";
   return true;
 }
@@ -472,9 +473,9 @@
   // Read new data in
   vector<char> new_data;
   TEST_AND_RETURN_FALSE(utils::ReadFile(new_filename, &new_data));
-  
+
   TEST_AND_RETURN_FALSE(!new_data.empty());
-  
+
   vector<char> new_data_bz;
   TEST_AND_RETURN_FALSE(BzipCompress(new_data, &new_data_bz));
   CHECK(!new_data_bz.empty());
@@ -516,15 +517,15 @@
       if (bsdiff_delta.size() < current_best_size) {
         operation.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
         current_best_size = bsdiff_delta.size();
-        
+
         data = bsdiff_delta;
       }
     }
   }
-  
+
   // Set parameters of the operations
   CHECK_EQ(data.size(), current_best_size);
-  
+
   if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE ||
       operation.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) {
     TEST_AND_RETURN_FALSE(
@@ -535,10 +536,10 @@
   TEST_AND_RETURN_FALSE(
       GatherExtents(new_filename, operation.mutable_dst_extents()));
   operation.set_dst_length(new_data.size());
-  
+
   out_data->swap(data);
   *out_op = operation;
-  
+
   return true;
 }
 
@@ -613,7 +614,7 @@
   TEST_AND_RETURN_FALSE(
       FindScratchSpace(blocks, blocks_required, &scratch_extents));
   LinearExtentAllocator scratch_allocator(scratch_extents);
-  
+
   uint64_t scratch_blocks_used = 0;
   for (set<Edge>::const_iterator it = edges.begin();
        it != edges.end(); ++it) {
@@ -628,7 +629,7 @@
         scratch_allocator.Allocate(graph_utils::EdgeWeight(*graph, *it));
     // create vertex to copy original->scratch
     graph->resize(graph->size() + 1);
-    
+
     // make node depend on the copy operation
     (*graph)[it->first].out_edges.insert(make_pair(graph->size() - 1,
                                                    EdgeProperties()));
@@ -743,9 +744,10 @@
     const string& old_image,
     const string& new_root,
     const string& new_image,
-    const std::string& old_kernel_part,
-    const std::string& new_kernel_part,
-    const string& output_path) {
+    const string& old_kernel_part,
+    const string& new_kernel_part,
+    const string& output_path,
+    const string& private_key_path) {
   struct stat old_image_stbuf;
   TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0);
   struct stat new_image_stbuf;
@@ -771,7 +773,7 @@
   }
   Graph graph;
   CheckGraph(graph);
-  
+
   const string kTempFileTemplate("/tmp/CrAU_temp_data.XXXXXX");
   string temp_file_path;
   off_t data_file_size = 0;
@@ -787,7 +789,7 @@
         utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd));
     TEST_AND_RETURN_FALSE(fd >= 0);
     ScopedFdCloser fd_closer(&fd);
-  
+
     TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph,
                                          &blocks,
                                          old_root,
@@ -795,12 +797,12 @@
                                          fd,
                                          &data_file_size));
     CheckGraph(graph);
-                                         
+
     TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks,
                                               fd,
                                               &data_file_size,
                                               new_image,
-                                              &final_op));  
+                                              &final_op));
 
     // Read kernel partition
     TEST_AND_RETURN_FALSE(DeltaCompressKernelPartition(old_kernel_part,
@@ -810,11 +812,11 @@
                                                        &data_file_size));
   }
   CheckGraph(graph);
-  
+
   LOG(INFO) << "Creating edges...";
   CreateEdges(&graph, blocks);
   CheckGraph(graph);
-  
+
   CycleBreaker cycle_breaker;
   LOG(INFO) << "Finding cycles...";
   set<Edge> cut_edges;
@@ -831,7 +833,7 @@
   LOG(INFO) << "Ordering...";
   TopologicalSort(graph, &final_order);
   CheckGraph(graph);
-  
+
   // Convert to protobuf Manifest object
   DeltaArchiveManifest manifest;
   CheckGraph(graph);
@@ -844,7 +846,7 @@
     CHECK(op->has_type());
     LOG(INFO) << "final op length: " << op->data_length();
   }
-  
+
   CheckGraph(graph);
   manifest.set_block_size(kBlockSize);
 
@@ -859,29 +861,29 @@
                                          ordered_blobs_path));
 
   // Check that install op blobs are in order and that all blocks are written.
+  uint64_t next_blob_offset = 0;
   {
     vector<uint32_t> written_count(blocks.size(), 0);
-    uint64_t next_blob_offset = 0;
     for (int i = 0; i < (manifest.install_operations_size() +
                          manifest.kernel_install_operations_size()); i++) {
-      const DeltaArchiveManifest_InstallOperation& op =
+      DeltaArchiveManifest_InstallOperation* op =
           i < manifest.install_operations_size() ?
-          manifest.install_operations(i) :
-          manifest.kernel_install_operations(
+          manifest.mutable_install_operations(i) :
+          manifest.mutable_kernel_install_operations(
               i - manifest.install_operations_size());
-      for (int j = 0; j < op.dst_extents_size(); j++) {
-        const Extent& extent = op.dst_extents(j);
+      for (int j = 0; j < op->dst_extents_size(); j++) {
+        const Extent& extent = op->dst_extents(j);
         for (uint64_t block = extent.start_block();
              block < (extent.start_block() + extent.num_blocks()); block++) {
           written_count[block]++;
         }
       }
-      if (op.has_data_offset()) {
-        if (op.data_offset() != next_blob_offset) {
-          LOG(FATAL) << "bad blob offset! " << op.data_offset() << " != "
+      if (op->has_data_offset()) {
+        if (op->data_offset() != next_blob_offset) {
+          LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != "
                      << next_blob_offset;
         }
-        next_blob_offset += op.data_length();
+        next_blob_offset += op->data_length();
       }
     }
     // check all blocks written to
@@ -892,9 +894,34 @@
     }
   }
 
+  // Signatures appear at the end of the blobs. Note the offset in the
+  // manifest
+  if (!private_key_path.empty()) {
+    LOG(INFO) << "Making room for signature in file";
+    manifest.set_signatures_offset(next_blob_offset);
+    LOG(INFO) << "set? " << manifest.has_signatures_offset();
+    // Add a dummy op at the end to appease older clients
+    DeltaArchiveManifest_InstallOperation* dummy_op =
+        manifest.add_kernel_install_operations();
+    dummy_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
+    dummy_op->set_data_offset(next_blob_offset);
+    manifest.set_signatures_offset(next_blob_offset);
+    uint64_t signature_blob_length = 0;
+    TEST_AND_RETURN_FALSE(
+        PayloadSigner::SignatureBlobLength(private_key_path,
+                                           &signature_blob_length));
+    dummy_op->set_data_length(signature_blob_length);
+    manifest.set_signatures_size(signature_blob_length);
+    Extent* dummy_extent = dummy_op->add_dst_extents();
+    // Tell the dummy op to write this data to a big sparse hole
+    dummy_extent->set_start_block(kSparseHole);
+    dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
+                                 kBlockSize);
+  }
+
   // Serialize protobuf
   string serialized_manifest;
-  
+
   CheckGraph(graph);
   TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
   CheckGraph(graph);
@@ -905,25 +932,25 @@
                                           O_WRONLY | O_CREAT | O_TRUNC,
                                           0644) == 0);
   ScopedFileWriterCloser writer_closer(&writer);
-  
+
   // Write header
   TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, strlen(kDeltaMagic)) ==
                         static_cast<ssize_t>(strlen(kDeltaMagic)));
-  
+
   // Write version number
   TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, kVersionNumber));
-  
+
   // Write protobuf length
   TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer,
                                                serialized_manifest.size()));
-  
+
   // Write protobuf
   LOG(INFO) << "Writing final delta file protobuf... "
             << serialized_manifest.size();
   TEST_AND_RETURN_FALSE(writer.Write(serialized_manifest.data(),
                                      serialized_manifest.size()) ==
                         static_cast<ssize_t>(serialized_manifest.size()));
-  
+
   // Append the data blobs
   LOG(INFO) << "Writing final delta file data blobs...";
   int blobs_fd = open(ordered_blobs_path.c_str(), O_RDONLY, 0);
@@ -939,7 +966,19 @@
     TEST_AND_RETURN_FALSE_ERRNO(rc > 0);
     TEST_AND_RETURN_FALSE(writer.Write(buf, rc) == rc);
   }
-  
+
+  // Write signature blob.
+  if (!private_key_path.empty()) {
+    LOG(INFO) << "Signing the update...";
+    vector<char> signature_blob;
+    TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(output_path,
+                                                     private_key_path,
+                                                     &signature_blob));
+    TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0],
+                                       signature_blob.size()) ==
+                          static_cast<ssize_t>(signature_blob.size()));
+  }
+
   LOG(INFO) << "All done. Successfully created delta file.";
   return true;
 }