blob: f5cd02ef102d0f70e9de238a08986b50df2fe9c1 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
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//
Andrew de los Reyes0c440052010-08-20 11:25:54 -070016
Alex Deymo923d8fa2014-07-15 17:58:51 -070017#include "update_engine/payload_generator/payload_signer.h"
Andrew de los Reyes0c440052010-08-20 11:25:54 -070018
Alex Deymo6f20dd42015-08-18 16:42:46 -070019#include <endian.h>
20
Darin Petkovb039d502010-12-03 09:08:04 -080021#include <base/logging.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070022#include <base/strings/string_split.h>
23#include <base/strings/string_util.h>
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070024#include <brillo/data_encoding.h>
Darin Petkovb039d502010-12-03 09:08:04 -080025#include <openssl/pem.h>
26
Sen Jiangaef1c6f2015-10-07 10:05:32 -070027#include "update_engine/delta_performer.h"
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070028#include "update_engine/omaha_hash_calculator.h"
Sen Jiangaef1c6f2015-10-07 10:05:32 -070029#include "update_engine/payload_constants.h"
30#include "update_engine/payload_generator/delta_diff_generator.h"
Alex Deymo14158572015-06-13 03:37:08 -070031#include "update_engine/payload_generator/payload_file.h"
Alex Deymo923d8fa2014-07-15 17:58:51 -070032#include "update_engine/payload_verifier.h"
Andrew de los Reyes0c440052010-08-20 11:25:54 -070033#include "update_engine/subprocess.h"
34#include "update_engine/update_metadata.pb.h"
35#include "update_engine/utils.h"
36
37using std::string;
38using std::vector;
39
40namespace chromeos_update_engine {
41
Darin Petkov9574f7e2011-01-13 10:48:12 -080042namespace {
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -070043
Alex Deymob552a682015-09-30 09:36:49 -070044// The payload verifier will check all the signatures included in the payload
45// regardless of the version field. Old version of the verifier require the
46// version field to be included and be 1.
47const uint32_t kSignatureMessageLegacyVersion = 1;
48
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070049// Given raw |signatures|, packs them into a protobuf and serializes it into a
Darin Petkov9574f7e2011-01-13 10:48:12 -080050// binary blob. Returns true on success, false otherwise.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070051bool ConvertSignatureToProtobufBlob(const vector<brillo::Blob>& signatures,
52 brillo::Blob* out_signature_blob) {
Darin Petkov9574f7e2011-01-13 10:48:12 -080053 // Pack it into a protobuf
54 Signatures out_message;
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070055 for (const brillo::Blob& signature : signatures) {
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070056 Signatures_Signature* sig_message = out_message.add_signatures();
Alex Deymob552a682015-09-30 09:36:49 -070057 // Set all the signatures with the same version number.
58 sig_message->set_version(kSignatureMessageLegacyVersion);
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070059 sig_message->set_data(signature.data(), signature.size());
60 }
Darin Petkov9574f7e2011-01-13 10:48:12 -080061
62 // Serialize protobuf
63 string serialized;
64 TEST_AND_RETURN_FALSE(out_message.AppendToString(&serialized));
65 out_signature_blob->insert(out_signature_blob->end(),
66 serialized.begin(),
67 serialized.end());
68 LOG(INFO) << "Signature blob size: " << out_signature_blob->size();
69 return true;
70}
71
72// Given an unsigned payload under |payload_path| and the |signature_blob_size|
73// generates an updated payload that includes a dummy signature op in its
Jay Srinivasan738fdf32012-12-07 17:40:54 -080074// manifest. It populates |out_metadata_size| with the size of the final
Don Garrett2ae37872013-10-25 13:33:20 -070075// manifest after adding the dummy signature operation, and
76// |out_signatures_offset| with the expected offset for the new blob. Returns
77// true on success, false otherwise.
Darin Petkovadb3cef2011-01-13 16:16:08 -080078bool AddSignatureOpToPayload(const string& payload_path,
Don Garrett2ae37872013-10-25 13:33:20 -070079 uint64_t signature_blob_size,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070080 brillo::Blob* out_payload,
Don Garrett2ae37872013-10-25 13:33:20 -070081 uint64_t* out_metadata_size,
82 uint64_t* out_signatures_offset) {
Darin Petkov9574f7e2011-01-13 10:48:12 -080083 const int kProtobufOffset = 20;
84 const int kProtobufSizeOffset = 12;
85
Darin Petkovadb3cef2011-01-13 16:16:08 -080086 // Loads the payload.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070087 brillo::Blob payload;
Darin Petkov9574f7e2011-01-13 10:48:12 -080088 DeltaArchiveManifest manifest;
Sen Jiangaef1c6f2015-10-07 10:05:32 -070089 uint64_t metadata_size, major_version;
90 uint32_t metadata_signature_size;
91 TEST_AND_RETURN_FALSE(PayloadSigner::LoadPayload(payload_path, &payload,
92 &manifest, &major_version, &metadata_size, &metadata_signature_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -080093
Don Garrett2ae37872013-10-25 13:33:20 -070094 // Is there already a signature op in place?
95 if (manifest.has_signatures_size()) {
Don Garrett2ae37872013-10-25 13:33:20 -070096 // The signature op is tied to the size of the signature blob, but not it's
97 // contents. We don't allow the manifest to change if there is already an op
98 // present, because that might invalidate previously generated
99 // hashes/signatures.
100 if (manifest.signatures_size() != signature_blob_size) {
101 LOG(ERROR) << "Attempt to insert different signature sized blob. "
102 << "(current:" << manifest.signatures_size()
103 << "new:" << signature_blob_size << ")";
104 return false;
105 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800106
Don Garrett2ae37872013-10-25 13:33:20 -0700107 LOG(INFO) << "Matching signature sizes already present.";
108 } else {
109 // Updates the manifest to include the signature operation.
Sen Jiangaef1c6f2015-10-07 10:05:32 -0700110 PayloadSigner::AddSignatureOp(payload.size() - metadata_size,
111 signature_blob_size,
112 &manifest);
Don Garrett2ae37872013-10-25 13:33:20 -0700113
114 // Updates the payload to include the new manifest.
115 string serialized_manifest;
116 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
117 LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
118 payload.erase(payload.begin() + kProtobufOffset,
119 payload.begin() + metadata_size);
120 payload.insert(payload.begin() + kProtobufOffset,
121 serialized_manifest.begin(),
122 serialized_manifest.end());
123
124 // Updates the protobuf size.
125 uint64_t size_be = htobe64(serialized_manifest.size());
126 memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
127 metadata_size = serialized_manifest.size() + kProtobufOffset;
128
129 LOG(INFO) << "Updated payload size: " << payload.size();
130 LOG(INFO) << "Updated metadata size: " << metadata_size;
131 }
132
Darin Petkov9574f7e2011-01-13 10:48:12 -0800133 out_payload->swap(payload);
Don Garrett2ae37872013-10-25 13:33:20 -0700134 *out_metadata_size = metadata_size;
135 *out_signatures_offset = metadata_size + manifest.signatures_offset();
136 LOG(INFO) << "Signature Blob Offset: " << *out_signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800137 return true;
138}
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700139} // namespace
Darin Petkov9574f7e2011-01-13 10:48:12 -0800140
Sen Jiangaef1c6f2015-10-07 10:05:32 -0700141void PayloadSigner::AddSignatureOp(uint64_t signature_blob_offset,
142 uint64_t signature_blob_length,
143 DeltaArchiveManifest* manifest) {
144 LOG(INFO) << "Making room for signature in file";
145 manifest->set_signatures_offset(signature_blob_offset);
146 LOG(INFO) << "set? " << manifest->has_signatures_offset();
147 // Add a dummy op at the end to appease older clients
148 InstallOperation* dummy_op = manifest->add_kernel_install_operations();
149 dummy_op->set_type(InstallOperation::REPLACE);
150 dummy_op->set_data_offset(signature_blob_offset);
151 manifest->set_signatures_offset(signature_blob_offset);
152 dummy_op->set_data_length(signature_blob_length);
153 manifest->set_signatures_size(signature_blob_length);
154 Extent* dummy_extent = dummy_op->add_dst_extents();
155 // Tell the dummy op to write this data to a big sparse hole
156 dummy_extent->set_start_block(kSparseHole);
157 dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
158 kBlockSize);
159}
160
161bool PayloadSigner::LoadPayload(const std::string& payload_path,
162 brillo::Blob* out_payload,
163 DeltaArchiveManifest* out_manifest,
164 uint64_t* out_major_version,
165 uint64_t* out_metadata_size,
166 uint32_t* out_metadata_signature_size) {
167 brillo::Blob payload;
168 TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
169 TEST_AND_RETURN_FALSE(payload.size() >=
170 DeltaPerformer::kMaxPayloadHeaderSize);
171 const uint8_t* read_pointer = payload.data();
172 TEST_AND_RETURN_FALSE(
173 memcmp(read_pointer, kDeltaMagic, sizeof(kDeltaMagic)) == 0);
174 read_pointer += sizeof(kDeltaMagic);
175
176 uint64_t major_version;
177 memcpy(&major_version, read_pointer, sizeof(major_version));
178 read_pointer += sizeof(major_version);
179 major_version = be64toh(major_version);
180 TEST_AND_RETURN_FALSE(major_version == kChromeOSMajorPayloadVersion ||
181 major_version == kBrilloMajorPayloadVersion);
182 if (out_major_version)
183 *out_major_version = major_version;
184
185 uint64_t manifest_size = 0;
186 memcpy(&manifest_size, read_pointer, sizeof(manifest_size));
187 read_pointer += sizeof(manifest_size);
188 manifest_size = be64toh(manifest_size);
189
190 uint32_t metadata_signature_size = 0;
191 if (major_version == kBrilloMajorPayloadVersion) {
192 memcpy(&metadata_signature_size, read_pointer,
193 sizeof(metadata_signature_size));
194 read_pointer += sizeof(metadata_signature_size);
195 metadata_signature_size = be32toh(metadata_signature_size);
196 }
197 if (out_metadata_signature_size)
198 *out_metadata_signature_size = metadata_signature_size;
199
200 *out_metadata_size = read_pointer - payload.data() + manifest_size;
201 TEST_AND_RETURN_FALSE(payload.size() >= *out_metadata_size);
202 if (out_manifest)
203 TEST_AND_RETURN_FALSE(
204 out_manifest->ParseFromArray(read_pointer, manifest_size));
205 *out_payload = std::move(payload);
206 return true;
207}
208
209bool PayloadSigner::VerifySignedPayload(const string& payload_path,
210 const string& public_key_path) {
211 brillo::Blob payload;
212 DeltaArchiveManifest manifest;
213 uint64_t metadata_size, major_version;
214 uint32_t metadata_signature_size;
215 TEST_AND_RETURN_FALSE(LoadPayload(payload_path, &payload, &manifest,
216 &major_version, &metadata_size, &metadata_signature_size));
217 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
218 manifest.has_signatures_size());
219 CHECK_EQ(payload.size(),
220 metadata_size + manifest.signatures_offset() +
221 manifest.signatures_size());
222 brillo::Blob signature_blob(
223 payload.begin() + metadata_size + manifest.signatures_offset(),
224 payload.end());
225 brillo::Blob hash;
226 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
227 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
228 TEST_AND_RETURN_FALSE(PayloadVerifier::PadRSA2048SHA256Hash(&hash));
229 TEST_AND_RETURN_FALSE(PayloadVerifier::VerifySignature(
230 signature_blob, public_key_path, hash));
231 return true;
232}
233
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700234bool PayloadSigner::SignHash(const brillo::Blob& hash,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800235 const string& private_key_path,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700236 brillo::Blob* out_signature) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700237 LOG(INFO) << "Signing hash with private key: " << private_key_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700238 string sig_path;
239 TEST_AND_RETURN_FALSE(
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700240 utils::MakeTempFile("signature.XXXXXX", &sig_path, nullptr));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700241 ScopedPathUnlinker sig_path_unlinker(sig_path);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700242
243 string hash_path;
244 TEST_AND_RETURN_FALSE(
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700245 utils::MakeTempFile("hash.XXXXXX", &hash_path, nullptr));
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700246 ScopedPathUnlinker hash_path_unlinker(hash_path);
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700247 // We expect unpadded SHA256 hash coming in
248 TEST_AND_RETURN_FALSE(hash.size() == 32);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700249 brillo::Blob padded_hash(hash);
Alex Deymo923d8fa2014-07-15 17:58:51 -0700250 PayloadVerifier::PadRSA2048SHA256Hash(&padded_hash);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700251 TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700252 padded_hash.data(),
253 padded_hash.size()));
Darin Petkovd22cb292010-09-29 10:02:29 -0700254
Alex Deymob552a682015-09-30 09:36:49 -0700255 // This runs on the server, so it's okay to copy out and call openssl
256 // executable rather than properly use the library.
257 vector<string> cmd = {"openssl", "rsautl", "-raw", "-sign", "-inkey",
258 private_key_path, "-in", hash_path, "-out", sig_path};
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700259 int return_code = 0;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700260 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code,
261 nullptr));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700262 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700263
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700264 brillo::Blob signature;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700265 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800266 out_signature->swap(signature);
267 return true;
268}
Darin Petkovd22cb292010-09-29 10:02:29 -0700269
Darin Petkov9574f7e2011-01-13 10:48:12 -0800270bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700271 const vector<string>& private_key_paths,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700272 brillo::Blob* out_signature_blob) {
273 brillo::Blob hash_data;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800274 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
275 unsigned_payload_path, -1, &hash_data) ==
276 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700277
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700278 vector<brillo::Blob> signatures;
Alex Deymo020600d2014-11-05 21:05:55 -0800279 for (const string& path : private_key_paths) {
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700280 brillo::Blob signature;
Alex Deymo020600d2014-11-05 21:05:55 -0800281 TEST_AND_RETURN_FALSE(SignHash(hash_data, path, &signature));
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700282 signatures.push_back(signature);
283 }
284 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800285 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700286 return true;
287}
288
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700289bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
290 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700291 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700292
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700293 string x_path;
294 TEST_AND_RETURN_FALSE(
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700295 utils::MakeTempFile("signed_data.XXXXXX", &x_path, nullptr));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700296 ScopedPathUnlinker x_path_unlinker(x_path);
297 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
298
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700299 brillo::Blob sig_blob;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700300 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700301 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700302 &sig_blob));
303 *out_length = sig_blob.size();
304 return true;
305}
306
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700307bool PayloadSigner::PrepPayloadForHashing(
308 const string& payload_path,
309 const vector<int>& signature_sizes,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700310 brillo::Blob* payload_out,
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700311 uint64_t* metadata_size_out,
312 uint64_t* signatures_offset_out) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800313 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
314
315 // Loads the payload and adds the signature op to it.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700316 vector<brillo::Blob> signatures;
Alex Deymo020600d2014-11-05 21:05:55 -0800317 for (int signature_size : signature_sizes) {
318 signatures.emplace_back(signature_size, 0);
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700319 }
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700320 brillo::Blob signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700321 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800322 &signature_blob));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800323 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
324 signature_blob.size(),
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700325 payload_out,
326 metadata_size_out,
327 signatures_offset_out));
Don Garrett2ae37872013-10-25 13:33:20 -0700328
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700329 return true;
330}
331
332bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
333 const vector<int>& signature_sizes,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700334 brillo::Blob* out_hash_data) {
335 brillo::Blob payload;
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700336 uint64_t metadata_size;
337 uint64_t signatures_offset;
338
339 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
340 signature_sizes,
341 &payload,
342 &metadata_size,
343 &signatures_offset));
Don Garrett2ae37872013-10-25 13:33:20 -0700344
345 // Calculates the hash on the updated payload. Note that we stop calculating
346 // before we reach the signature information.
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800347 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(payload.data(),
Don Garrett2ae37872013-10-25 13:33:20 -0700348 signatures_offset,
349 out_hash_data));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800350 return true;
351}
352
Jay Srinivasanf4318702012-09-24 11:56:24 -0700353bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700354 const vector<int>& signature_sizes,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700355 brillo::Blob* out_metadata_hash) {
356 brillo::Blob payload;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700357 uint64_t metadata_size;
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700358 uint64_t signatures_offset;
359
360 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
361 signature_sizes,
362 &payload,
363 &metadata_size,
364 &signatures_offset));
Jay Srinivasanf4318702012-09-24 11:56:24 -0700365
366 // Calculates the hash on the manifest.
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800367 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(payload.data(),
Jay Srinivasanf4318702012-09-24 11:56:24 -0700368 metadata_size,
369 out_metadata_hash));
370 return true;
371}
372
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700373bool PayloadSigner::AddSignatureToPayload(
374 const string& payload_path,
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700375 const vector<brillo::Blob>& signatures,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800376 const string& signed_payload_path,
377 uint64_t *out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800378 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
379
380 // Loads the payload and adds the signature op to it.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700381 brillo::Blob signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700382 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800383 &signature_blob));
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700384 brillo::Blob payload;
Don Garrett2ae37872013-10-25 13:33:20 -0700385 uint64_t signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800386 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
387 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800388 &payload,
Don Garrett2ae37872013-10-25 13:33:20 -0700389 out_metadata_size,
390 &signatures_offset));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800391 // Appends the signature blob to the end of the payload and writes the new
392 // payload.
Don Garrett2ae37872013-10-25 13:33:20 -0700393 LOG(INFO) << "Payload size before signatures: " << payload.size();
394 payload.resize(signatures_offset);
395 payload.insert(payload.begin() + signatures_offset,
396 signature_blob.begin(),
397 signature_blob.end());
Darin Petkov9574f7e2011-01-13 10:48:12 -0800398 LOG(INFO) << "Signed payload size: " << payload.size();
399 TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
400 payload.data(),
401 payload.size()));
402 return true;
403}
404
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800405bool PayloadSigner::GetMetadataSignature(const void* const metadata,
Jay Srinivasanf4318702012-09-24 11:56:24 -0700406 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700407 const string& private_key_path,
408 string* out_signature) {
409 // Calculates the hash on the updated payload. Note that the payload includes
410 // the signature op but doesn't include the signature blob at the end.
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700411 brillo::Blob metadata_hash;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700412 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
413 metadata_size,
414 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700415
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700416 brillo::Blob signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700417 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700418 private_key_path,
419 &signature));
420
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700421 *out_signature = brillo::data_encoding::Base64Encode(signature);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700422 return true;
423}
424
425
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700426} // namespace chromeos_update_engine