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.
ConvertSignatureToProtobufBlob(const vector<brillo::Blob> & signatures,brillo::Blob * out_signature_blob)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.
AddSignatureBlobToPayload(const string & payload_path,const brillo::Blob & signature_blob,const brillo::Blob & metadata_signature_blob,brillo::Blob * out_payload,uint64_t * out_metadata_size,uint32_t * out_metadata_signature_size,uint64_t * out_signatures_offset)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|.
CalculateHashFromPayload(const brillo::Blob & payload,const uint64_t metadata_size,const uint32_t metadata_signature_size,const uint64_t signatures_offset,brillo::Blob * out_hash_data,brillo::Blob * 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 
AddSignatureToManifest(uint64_t signature_blob_offset,uint64_t signature_blob_length,bool add_dummy_op,DeltaArchiveManifest * manifest)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 
LoadPayloadMetadata(const string & payload_path,brillo::Blob * out_payload_metadata,DeltaArchiveManifest * out_manifest,uint64_t * out_major_version,uint64_t * out_metadata_size,uint32_t * out_metadata_signature_size)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 
VerifySignedPayload(const string & payload_path,const string & public_key_path)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 
SignHash(const brillo::Blob & hash,const string & private_key_path,brillo::Blob * out_signature)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 
SignHashWithKeys(const brillo::Blob & hash_data,const vector<string> & private_key_paths,brillo::Blob * out_signature_blob)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 
SignPayload(const string & unsigned_payload_path,const vector<string> & private_key_paths,const uint64_t metadata_size,const uint32_t metadata_signature_size,const uint64_t signatures_offset,brillo::Blob * out_signature_blob)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 
SignatureBlobLength(const vector<string> & private_key_paths,uint64_t * out_length)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 
HashPayloadForSigning(const string & payload_path,const vector<int> & signature_sizes,brillo::Blob * out_payload_hash_data,brillo::Blob * out_metadata_hash)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 
AddSignatureToPayload(const string & payload_path,const vector<brillo::Blob> & payload_signatures,const vector<brillo::Blob> & metadata_signatures,const string & signed_payload_path,uint64_t * out_metadata_size)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 
GetMetadataSignature(const void * const metadata,size_t metadata_size,const string & private_key_path,string * out_signature)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 
ExtractPayloadProperties(const string & payload_path,brillo::KeyValueStore * properties)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