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