Home | History | Annotate | Download | only in payload_generator
      1 //
      2 // Copyright (C) 2011 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "update_engine/payload_generator/payload_signer.h"
     18 
     19 #include <endian.h>
     20 
     21 #include <base/logging.h>
     22 #include <base/strings/string_number_conversions.h>
     23 #include <base/strings/string_split.h>
     24 #include <base/strings/string_util.h>
     25 #include <brillo/data_encoding.h>
     26 #include <brillo/streams/file_stream.h>
     27 #include <brillo/streams/stream.h>
     28 #include <openssl/err.h>
     29 #include <openssl/pem.h>
     30 
     31 #include "update_engine/common/hash_calculator.h"
     32 #include "update_engine/common/subprocess.h"
     33 #include "update_engine/common/utils.h"
     34 #include "update_engine/payload_consumer/delta_performer.h"
     35 #include "update_engine/payload_consumer/payload_constants.h"
     36 #include "update_engine/payload_consumer/payload_verifier.h"
     37 #include "update_engine/payload_generator/delta_diff_generator.h"
     38 #include "update_engine/payload_generator/payload_file.h"
     39 #include "update_engine/update_metadata.pb.h"
     40 
     41 using std::string;
     42 using std::vector;
     43 
     44 namespace chromeos_update_engine {
     45 
     46 namespace {
     47 
     48 // The payload verifier will check all the signatures included in the payload
     49 // regardless of the version field. Old version of the verifier require the
     50 // version field to be included and be 1.
     51 const uint32_t kSignatureMessageLegacyVersion = 1;
     52 
     53 // Given raw |signatures|, packs them into a protobuf and serializes it into a
     54 // binary blob. Returns true on success, false otherwise.
     55 bool ConvertSignatureToProtobufBlob(const vector<brillo::Blob>& signatures,
     56                                     brillo::Blob* out_signature_blob) {
     57   // Pack it into a protobuf
     58   Signatures out_message;
     59   for (const brillo::Blob& signature : signatures) {
     60     Signatures_Signature* sig_message = out_message.add_signatures();
     61     // Set all the signatures with the same version number.
     62     sig_message->set_version(kSignatureMessageLegacyVersion);
     63     sig_message->set_data(signature.data(), signature.size());
     64   }
     65 
     66   // Serialize protobuf
     67   string serialized;
     68   TEST_AND_RETURN_FALSE(out_message.AppendToString(&serialized));
     69   out_signature_blob->insert(out_signature_blob->end(),
     70                              serialized.begin(),
     71                              serialized.end());
     72   LOG(INFO) << "Signature blob size: " << out_signature_blob->size();
     73   return true;
     74 }
     75 
     76 // Given an unsigned payload under |payload_path| and the |signature_blob| and
     77 // |metadata_signature_blob| generates an updated payload that includes the
     78 // signatures. It populates |out_metadata_size| with the size of the final
     79 // manifest after adding the dummy signature operation, and
     80 // |out_signatures_offset| with the expected offset for the new blob, and
     81 // |out_metadata_signature_size| which will be size of |metadata_signature_blob|
     82 // if the payload major version supports metadata signature, 0 otherwise.
     83 // Returns true on success, false otherwise.
     84 bool AddSignatureBlobToPayload(const string& payload_path,
     85                                const brillo::Blob& signature_blob,
     86                                const brillo::Blob& metadata_signature_blob,
     87                                brillo::Blob* out_payload,
     88                                uint64_t* out_metadata_size,
     89                                uint32_t* out_metadata_signature_size,
     90                                uint64_t* out_signatures_offset) {
     91   uint64_t manifest_offset = 20;
     92   const int kProtobufSizeOffset = 12;
     93 
     94   DeltaArchiveManifest manifest;
     95   uint64_t metadata_size, major_version;
     96   uint32_t metadata_signature_size;
     97   TEST_AND_RETURN_FALSE(
     98       PayloadSigner::LoadPayloadMetadata(payload_path,
     99                                          nullptr,
    100                                          &manifest,
    101                                          &major_version,
    102                                          &metadata_size,
    103                                          &metadata_signature_size));
    104 
    105   brillo::Blob payload;
    106   TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
    107 
    108   if (major_version == kBrilloMajorPayloadVersion) {
    109     // Write metadata signature size in header.
    110     uint32_t metadata_signature_size_be =
    111         htobe32(metadata_signature_blob.size());
    112     memcpy(payload.data() + manifest_offset, &metadata_signature_size_be,
    113            sizeof(metadata_signature_size_be));
    114     manifest_offset += sizeof(metadata_signature_size_be);
    115     // Replace metadata signature.
    116     payload.erase(payload.begin() + metadata_size,
    117                   payload.begin() + metadata_size + metadata_signature_size);
    118     payload.insert(payload.begin() + metadata_size,
    119                    metadata_signature_blob.begin(),
    120                    metadata_signature_blob.end());
    121     metadata_signature_size = metadata_signature_blob.size();
    122     LOG(INFO) << "Metadata signature size: " << metadata_signature_size;
    123   }
    124 
    125   // Is there already a signature op in place?
    126   if (manifest.has_signatures_size()) {
    127     // The signature op is tied to the size of the signature blob, but not it's
    128     // contents. We don't allow the manifest to change if there is already an op
    129     // present, because that might invalidate previously generated
    130     // hashes/signatures.
    131     if (manifest.signatures_size() != signature_blob.size()) {
    132       LOG(ERROR) << "Attempt to insert different signature sized blob. "
    133                  << "(current:" << manifest.signatures_size()
    134                  << "new:" << signature_blob.size() << ")";
    135       return false;
    136     }
    137 
    138     LOG(INFO) << "Matching signature sizes already present.";
    139   } else {
    140     // Updates the manifest to include the signature operation.
    141     PayloadSigner::AddSignatureToManifest(
    142         payload.size() - metadata_size - metadata_signature_size,
    143         signature_blob.size(),
    144         major_version == kChromeOSMajorPayloadVersion,
    145         &manifest);
    146 
    147     // Updates the payload to include the new manifest.
    148     string serialized_manifest;
    149     TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
    150     LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
    151     payload.erase(payload.begin() + manifest_offset,
    152                   payload.begin() + metadata_size);
    153     payload.insert(payload.begin() + manifest_offset,
    154                    serialized_manifest.begin(),
    155                    serialized_manifest.end());
    156 
    157     // Updates the protobuf size.
    158     uint64_t size_be = htobe64(serialized_manifest.size());
    159     memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
    160     metadata_size = serialized_manifest.size() + manifest_offset;
    161 
    162     LOG(INFO) << "Updated payload size: " << payload.size();
    163     LOG(INFO) << "Updated metadata size: " << metadata_size;
    164   }
    165   uint64_t signatures_offset = metadata_size + metadata_signature_size +
    166                                manifest.signatures_offset();
    167   LOG(INFO) << "Signature Blob Offset: " << signatures_offset;
    168   payload.resize(signatures_offset);
    169   payload.insert(payload.begin() + signatures_offset,
    170                  signature_blob.begin(),
    171                  signature_blob.end());
    172 
    173   *out_payload = std::move(payload);
    174   *out_metadata_size = metadata_size;
    175   *out_metadata_signature_size = metadata_signature_size;
    176   *out_signatures_offset = signatures_offset;
    177   return true;
    178 }
    179 
    180 // Given a |payload| with correct signature op and metadata signature size in
    181 // header and |metadata_size|, |metadata_signature_size|, |signatures_offset|,
    182 // calculate hash for payload and metadata, save it to |out_hash_data| and
    183 // |out_metadata_hash|.
    184 bool CalculateHashFromPayload(const brillo::Blob& payload,
    185                               const uint64_t metadata_size,
    186                               const uint32_t metadata_signature_size,
    187                               const uint64_t signatures_offset,
    188                               brillo::Blob* out_hash_data,
    189                               brillo::Blob* out_metadata_hash) {
    190   if (out_metadata_hash) {
    191     // Calculates the hash on the manifest.
    192     TEST_AND_RETURN_FALSE(
    193         HashCalculator::RawHashOfBytes(payload.data(), metadata_size,
    194                                        out_metadata_hash));
    195   }
    196   if (out_hash_data) {
    197     // Calculates the hash on the updated payload. Note that we skip metadata
    198     // signature and payload signature.
    199     HashCalculator calc;
    200     TEST_AND_RETURN_FALSE(calc.Update(payload.data(), metadata_size));
    201     TEST_AND_RETURN_FALSE(signatures_offset >=
    202                           metadata_size + metadata_signature_size);
    203     TEST_AND_RETURN_FALSE(calc.Update(
    204         payload.data() + metadata_size + metadata_signature_size,
    205         signatures_offset - metadata_size - metadata_signature_size));
    206     TEST_AND_RETURN_FALSE(calc.Finalize());
    207     *out_hash_data = calc.raw_hash();
    208   }
    209   return true;
    210 }
    211 
    212 }  // namespace
    213 
    214 void PayloadSigner::AddSignatureToManifest(uint64_t signature_blob_offset,
    215                                            uint64_t signature_blob_length,
    216                                            bool add_dummy_op,
    217                                            DeltaArchiveManifest* manifest) {
    218   LOG(INFO) << "Making room for signature in file";
    219   manifest->set_signatures_offset(signature_blob_offset);
    220   LOG(INFO) << "set? " << manifest->has_signatures_offset();
    221   manifest->set_signatures_offset(signature_blob_offset);
    222   manifest->set_signatures_size(signature_blob_length);
    223   // Add a dummy op at the end to appease older clients
    224   if (add_dummy_op) {
    225     InstallOperation* dummy_op = manifest->add_kernel_install_operations();
    226     dummy_op->set_type(InstallOperation::REPLACE);
    227     dummy_op->set_data_offset(signature_blob_offset);
    228     dummy_op->set_data_length(signature_blob_length);
    229     Extent* dummy_extent = dummy_op->add_dst_extents();
    230     // Tell the dummy op to write this data to a big sparse hole
    231     dummy_extent->set_start_block(kSparseHole);
    232     dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
    233                                  kBlockSize);
    234   }
    235 }
    236 
    237 bool PayloadSigner::LoadPayloadMetadata(const string& payload_path,
    238                                         brillo::Blob* out_payload_metadata,
    239                                         DeltaArchiveManifest* out_manifest,
    240                                         uint64_t* out_major_version,
    241                                         uint64_t* out_metadata_size,
    242                                         uint32_t* out_metadata_signature_size) {
    243   brillo::StreamPtr payload_file =
    244       brillo::FileStream::Open(base::FilePath(payload_path),
    245                                brillo::Stream::AccessMode::READ,
    246                                brillo::FileStream::Disposition::OPEN_EXISTING,
    247                                nullptr);
    248   TEST_AND_RETURN_FALSE(payload_file);
    249   brillo::Blob payload_metadata;
    250 
    251   payload_metadata.resize(DeltaPerformer::kMaxPayloadHeaderSize);
    252   TEST_AND_RETURN_FALSE(payload_file->ReadAllBlocking(
    253       payload_metadata.data(), payload_metadata.size(), nullptr));
    254 
    255   const uint8_t* read_pointer = payload_metadata.data();
    256   TEST_AND_RETURN_FALSE(
    257       memcmp(read_pointer, kDeltaMagic, sizeof(kDeltaMagic)) == 0);
    258   read_pointer += sizeof(kDeltaMagic);
    259 
    260   uint64_t major_version;
    261   memcpy(&major_version, read_pointer, sizeof(major_version));
    262   read_pointer += sizeof(major_version);
    263   major_version = be64toh(major_version);
    264   TEST_AND_RETURN_FALSE(major_version == kChromeOSMajorPayloadVersion ||
    265                         major_version == kBrilloMajorPayloadVersion);
    266   if (out_major_version)
    267     *out_major_version = major_version;
    268 
    269   uint64_t manifest_size = 0;
    270   memcpy(&manifest_size, read_pointer, sizeof(manifest_size));
    271   read_pointer += sizeof(manifest_size);
    272   manifest_size = be64toh(manifest_size);
    273 
    274   uint32_t metadata_signature_size = 0;
    275   if (major_version == kBrilloMajorPayloadVersion) {
    276     memcpy(&metadata_signature_size, read_pointer,
    277            sizeof(metadata_signature_size));
    278     read_pointer += sizeof(metadata_signature_size);
    279     metadata_signature_size = be32toh(metadata_signature_size);
    280   }
    281   if (out_metadata_signature_size)
    282     *out_metadata_signature_size = metadata_signature_size;
    283 
    284   uint64_t header_size = read_pointer - payload_metadata.data();
    285   uint64_t metadata_size = header_size + manifest_size;
    286   if (out_metadata_size)
    287     *out_metadata_size = metadata_size;
    288 
    289   size_t bytes_read = payload_metadata.size();
    290   payload_metadata.resize(metadata_size);
    291   TEST_AND_RETURN_FALSE(
    292       payload_file->ReadAllBlocking(payload_metadata.data() + bytes_read,
    293                                     payload_metadata.size() - bytes_read,
    294                                     nullptr));
    295   if (out_manifest) {
    296     TEST_AND_RETURN_FALSE(out_manifest->ParseFromArray(
    297         payload_metadata.data() + header_size, manifest_size));
    298   }
    299   if (out_payload_metadata)
    300     *out_payload_metadata = std::move(payload_metadata);
    301   return true;
    302 }
    303 
    304 bool PayloadSigner::VerifySignedPayload(const string& payload_path,
    305                                         const string& public_key_path) {
    306   DeltaArchiveManifest manifest;
    307   uint64_t metadata_size;
    308   uint32_t metadata_signature_size;
    309   TEST_AND_RETURN_FALSE(LoadPayloadMetadata(payload_path,
    310                                             nullptr,
    311                                             &manifest,
    312                                             nullptr,
    313                                             &metadata_size,
    314                                             &metadata_signature_size));
    315   brillo::Blob payload;
    316   TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
    317   TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
    318                         manifest.has_signatures_size());
    319   uint64_t signatures_offset = metadata_size + metadata_signature_size +
    320                                manifest.signatures_offset();
    321   CHECK_EQ(payload.size(), signatures_offset + manifest.signatures_size());
    322   brillo::Blob payload_hash, metadata_hash;
    323   TEST_AND_RETURN_FALSE(CalculateHashFromPayload(payload,
    324                                                  metadata_size,
    325                                                  metadata_signature_size,
    326                                                  signatures_offset,
    327                                                  &payload_hash,
    328                                                  &metadata_hash));
    329   brillo::Blob signature_blob(payload.begin() + signatures_offset,
    330                               payload.end());
    331   TEST_AND_RETURN_FALSE(PayloadVerifier::PadRSA2048SHA256Hash(&payload_hash));
    332   TEST_AND_RETURN_FALSE(PayloadVerifier::VerifySignature(
    333       signature_blob, public_key_path, payload_hash));
    334   if (metadata_signature_size) {
    335     signature_blob.assign(payload.begin() + metadata_size,
    336                           payload.begin() + metadata_size +
    337                           metadata_signature_size);
    338     TEST_AND_RETURN_FALSE(
    339         PayloadVerifier::PadRSA2048SHA256Hash(&metadata_hash));
    340     TEST_AND_RETURN_FALSE(PayloadVerifier::VerifySignature(
    341         signature_blob, public_key_path, metadata_hash));
    342   }
    343   return true;
    344 }
    345 
    346 bool PayloadSigner::SignHash(const brillo::Blob& hash,
    347                              const string& private_key_path,
    348                              brillo::Blob* out_signature) {
    349   LOG(INFO) << "Signing hash with private key: " << private_key_path;
    350   // We expect unpadded SHA256 hash coming in
    351   TEST_AND_RETURN_FALSE(hash.size() == 32);
    352   brillo::Blob padded_hash(hash);
    353   PayloadVerifier::PadRSA2048SHA256Hash(&padded_hash);
    354 
    355   // The code below executes the equivalent of:
    356   //
    357   // openssl rsautl -raw -sign -inkey |private_key_path|
    358   //   -in |padded_hash| -out |out_signature|
    359 
    360   FILE* fprikey = fopen(private_key_path.c_str(), "rb");
    361   TEST_AND_RETURN_FALSE(fprikey != nullptr);
    362   RSA* rsa = PEM_read_RSAPrivateKey(fprikey, nullptr, nullptr, nullptr);
    363   fclose(fprikey);
    364   TEST_AND_RETURN_FALSE(rsa != nullptr);
    365   brillo::Blob signature(RSA_size(rsa));
    366   ssize_t signature_size = RSA_private_encrypt(padded_hash.size(),
    367                                                padded_hash.data(),
    368                                                signature.data(),
    369                                                rsa,
    370                                                RSA_NO_PADDING);
    371   RSA_free(rsa);
    372   if (signature_size < 0) {
    373     LOG(ERROR) << "Signing hash failed: "
    374                << ERR_error_string(ERR_get_error(), nullptr);
    375     return false;
    376   }
    377   TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
    378                         signature.size());
    379   out_signature->swap(signature);
    380   return true;
    381 }
    382 
    383 bool PayloadSigner::SignHashWithKeys(const brillo::Blob& hash_data,
    384                                      const vector<string>& private_key_paths,
    385                                      brillo::Blob* out_signature_blob) {
    386   vector<brillo::Blob> signatures;
    387   for (const string& path : private_key_paths) {
    388     brillo::Blob signature;
    389     TEST_AND_RETURN_FALSE(SignHash(hash_data, path, &signature));
    390     signatures.push_back(signature);
    391   }
    392   TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
    393                                                        out_signature_blob));
    394   return true;
    395 }
    396 
    397 bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
    398                                 const vector<string>& private_key_paths,
    399                                 const uint64_t metadata_size,
    400                                 const uint32_t metadata_signature_size,
    401                                 const uint64_t signatures_offset,
    402                                 brillo::Blob* out_signature_blob) {
    403   brillo::Blob payload;
    404   TEST_AND_RETURN_FALSE(utils::ReadFile(unsigned_payload_path, &payload));
    405   brillo::Blob hash_data;
    406   TEST_AND_RETURN_FALSE(CalculateHashFromPayload(payload,
    407                                                  metadata_size,
    408                                                  metadata_signature_size,
    409                                                  signatures_offset,
    410                                                  &hash_data,
    411                                                  nullptr));
    412   TEST_AND_RETURN_FALSE(SignHashWithKeys(hash_data,
    413                                          private_key_paths,
    414                                          out_signature_blob));
    415   return true;
    416 }
    417 
    418 bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
    419                                         uint64_t* out_length) {
    420   DCHECK(out_length);
    421   brillo::Blob x_blob(1, 'x'), hash_blob, sig_blob;
    422   TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfBytes(x_blob.data(),
    423                                                        x_blob.size(),
    424                                                        &hash_blob));
    425   TEST_AND_RETURN_FALSE(
    426       SignHashWithKeys(hash_blob, private_key_paths, &sig_blob));
    427   *out_length = sig_blob.size();
    428   return true;
    429 }
    430 
    431 bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
    432                                           const vector<int>& signature_sizes,
    433                                           brillo::Blob* out_payload_hash_data,
    434                                           brillo::Blob* out_metadata_hash) {
    435   // Create a signature blob with signatures filled with 0.
    436   // Will be used for both payload signature and metadata signature.
    437   vector<brillo::Blob> signatures;
    438   for (int signature_size : signature_sizes) {
    439     signatures.emplace_back(signature_size, 0);
    440   }
    441   brillo::Blob signature_blob;
    442   TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
    443                                                        &signature_blob));
    444 
    445   brillo::Blob payload;
    446   uint64_t metadata_size, signatures_offset;
    447   uint32_t metadata_signature_size;
    448   // Prepare payload for hashing.
    449   TEST_AND_RETURN_FALSE(AddSignatureBlobToPayload(payload_path,
    450                                                   signature_blob,
    451                                                   signature_blob,
    452                                                   &payload,
    453                                                   &metadata_size,
    454                                                   &metadata_signature_size,
    455                                                   &signatures_offset));
    456   TEST_AND_RETURN_FALSE(CalculateHashFromPayload(payload,
    457                                                  metadata_size,
    458                                                  metadata_signature_size,
    459                                                  signatures_offset,
    460                                                  out_payload_hash_data,
    461                                                  out_metadata_hash));
    462   return true;
    463 }
    464 
    465 bool PayloadSigner::AddSignatureToPayload(
    466     const string& payload_path,
    467     const vector<brillo::Blob>& payload_signatures,
    468     const vector<brillo::Blob>& metadata_signatures,
    469     const string& signed_payload_path,
    470     uint64_t *out_metadata_size) {
    471   // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
    472 
    473   // Loads the payload and adds the signature op to it.
    474   brillo::Blob signature_blob, metadata_signature_blob;
    475   TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(payload_signatures,
    476                                                        &signature_blob));
    477   if (!metadata_signatures.empty()) {
    478     TEST_AND_RETURN_FALSE(
    479         ConvertSignatureToProtobufBlob(metadata_signatures,
    480                                        &metadata_signature_blob));
    481   }
    482   brillo::Blob payload;
    483   uint64_t signatures_offset;
    484   uint32_t metadata_signature_size;
    485   TEST_AND_RETURN_FALSE(AddSignatureBlobToPayload(payload_path,
    486                                                   signature_blob,
    487                                                   metadata_signature_blob,
    488                                                   &payload,
    489                                                   out_metadata_size,
    490                                                   &metadata_signature_size,
    491                                                   &signatures_offset));
    492 
    493   LOG(INFO) << "Signed payload size: " << payload.size();
    494   TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
    495                                          payload.data(),
    496                                          payload.size()));
    497   return true;
    498 }
    499 
    500 bool PayloadSigner::GetMetadataSignature(const void* const metadata,
    501                                          size_t metadata_size,
    502                                          const string& private_key_path,
    503                                          string* out_signature) {
    504   // Calculates the hash on the updated payload. Note that the payload includes
    505   // the signature op but doesn't include the signature blob at the end.
    506   brillo::Blob metadata_hash;
    507   TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfBytes(metadata,
    508                                                        metadata_size,
    509                                                        &metadata_hash));
    510 
    511   brillo::Blob signature;
    512   TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
    513                                  private_key_path,
    514                                  &signature));
    515 
    516   *out_signature = brillo::data_encoding::Base64Encode(signature);
    517   return true;
    518 }
    519 
    520 bool PayloadSigner::ExtractPayloadProperties(
    521     const string& payload_path, brillo::KeyValueStore* properties) {
    522   DeltaArchiveManifest manifest;
    523   brillo::Blob payload_metadata;
    524   uint64_t major_version, metadata_size;
    525   uint32_t metadata_signature_size;
    526   uint64_t file_size = utils::FileSize(payload_path);
    527 
    528   TEST_AND_RETURN_FALSE(
    529       PayloadSigner::LoadPayloadMetadata(payload_path,
    530                                          &payload_metadata,
    531                                          &manifest,
    532                                          &major_version,
    533                                          &metadata_size,
    534                                          &metadata_signature_size));
    535 
    536   properties->SetString(kPayloadPropertyFileSize, std::to_string(file_size));
    537   properties->SetString(kPayloadPropertyMetadataSize,
    538                         std::to_string(metadata_size));
    539 
    540   brillo::Blob file_hash, metadata_hash;
    541   TEST_AND_RETURN_FALSE(
    542       HashCalculator::RawHashOfFile(payload_path, file_size, &file_hash) ==
    543       static_cast<off_t>(file_size));
    544   TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfBytes(
    545       payload_metadata.data(), payload_metadata.size(), &metadata_hash));
    546 
    547   properties->SetString(kPayloadPropertyFileHash,
    548                         brillo::data_encoding::Base64Encode(file_hash));
    549   properties->SetString(kPayloadPropertyMetadataHash,
    550                         brillo::data_encoding::Base64Encode(metadata_hash));
    551   return true;
    552 }
    553 
    554 }  // namespace chromeos_update_engine
    555