blob: b75f393c550807d1bf2170932e147f9c3075050d [file] [log] [blame]
Darin Petkov85d02b72011-05-17 13:25:51 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Andrew de los Reyes0c440052010-08-20 11:25:54 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/payload_signer.h"
6
Darin Petkovb039d502010-12-03 09:08:04 -08007#include <base/logging.h>
Chris Masoned903c3b2011-05-12 15:35:46 -07008#include <base/string_split.h>
Darin Petkovb039d502010-12-03 09:08:04 -08009#include <base/string_util.h>
10#include <openssl/pem.h>
11
Darin Petkov9574f7e2011-01-13 10:48:12 -080012#include "update_engine/delta_diff_generator.h"
13#include "update_engine/delta_performer.h"
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070014#include "update_engine/omaha_hash_calculator.h"
Andrew de los Reyes0c440052010-08-20 11:25:54 -070015#include "update_engine/subprocess.h"
16#include "update_engine/update_metadata.pb.h"
17#include "update_engine/utils.h"
18
19using std::string;
20using std::vector;
21
22namespace chromeos_update_engine {
23
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070024const uint32_t kSignatureMessageOriginalVersion = 1;
25const uint32_t kSignatureMessageCurrentVersion = 1;
Andrew de los Reyes0c440052010-08-20 11:25:54 -070026
Darin Petkov9574f7e2011-01-13 10:48:12 -080027namespace {
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -070028
Han Shen2643cb72012-06-26 14:45:33 -070029const unsigned char kRSA2048SHA256Padding[] = {
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -070030 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
32 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
35 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
37 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
46 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
47 0x00, 0x04, 0x20
48};
49
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070050// Given raw |signatures|, packs them into a protobuf and serializes it into a
Darin Petkov9574f7e2011-01-13 10:48:12 -080051// binary blob. Returns true on success, false otherwise.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070052bool ConvertSignatureToProtobufBlob(const vector<vector<char> >& signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -080053 vector<char>* out_signature_blob) {
54 // Pack it into a protobuf
55 Signatures out_message;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070056 uint32_t version = kSignatureMessageOriginalVersion;
57 LOG_IF(WARNING, kSignatureMessageCurrentVersion -
58 kSignatureMessageOriginalVersion + 1 < signatures.size())
Jay Srinivasan51dcf262012-09-13 17:24:32 -070059 << "You may want to support clients in the range ["
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070060 << kSignatureMessageOriginalVersion << ", "
61 << kSignatureMessageCurrentVersion << "] inclusive, but you only "
62 << "provided " << signatures.size() << " signatures.";
63 for (vector<vector<char> >::const_iterator it = signatures.begin(),
64 e = signatures.end(); it != e; ++it) {
65 const vector<char>& signature = *it;
66 Signatures_Signature* sig_message = out_message.add_signatures();
67 sig_message->set_version(version++);
68 sig_message->set_data(signature.data(), signature.size());
69 }
Darin Petkov9574f7e2011-01-13 10:48:12 -080070
71 // Serialize protobuf
72 string serialized;
73 TEST_AND_RETURN_FALSE(out_message.AppendToString(&serialized));
74 out_signature_blob->insert(out_signature_blob->end(),
75 serialized.begin(),
76 serialized.end());
77 LOG(INFO) << "Signature blob size: " << out_signature_blob->size();
78 return true;
79}
80
81// Given an unsigned payload under |payload_path| and the |signature_blob_size|
82// generates an updated payload that includes a dummy signature op in its
83// manifest. Returns true on success, false otherwise.
Darin Petkovadb3cef2011-01-13 16:16:08 -080084bool AddSignatureOpToPayload(const string& payload_path,
Darin Petkov9574f7e2011-01-13 10:48:12 -080085 int signature_blob_size,
86 vector<char>* out_payload) {
87 const int kProtobufOffset = 20;
88 const int kProtobufSizeOffset = 12;
89
Darin Petkovadb3cef2011-01-13 16:16:08 -080090 // Loads the payload.
Darin Petkov9574f7e2011-01-13 10:48:12 -080091 vector<char> payload;
Darin Petkov9574f7e2011-01-13 10:48:12 -080092 DeltaArchiveManifest manifest;
Darin Petkovadb3cef2011-01-13 16:16:08 -080093 uint64_t metadata_size;
Jay Srinivasanf4318702012-09-24 11:56:24 -070094 TEST_AND_RETURN_FALSE(PayloadSigner::LoadPayload(
Darin Petkovadb3cef2011-01-13 16:16:08 -080095 payload_path, &payload, &manifest, &metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -080096 TEST_AND_RETURN_FALSE(!manifest.has_signatures_offset() &&
97 !manifest.has_signatures_size());
98
99 // Updates the manifest to include the signature operation.
100 DeltaDiffGenerator::AddSignatureOp(payload.size() - metadata_size,
101 signature_blob_size,
102 &manifest);
103
104 // Updates the payload to include the new manifest.
105 string serialized_manifest;
106 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
107 LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
108 payload.erase(payload.begin() + kProtobufOffset,
109 payload.begin() + metadata_size);
110 payload.insert(payload.begin() + kProtobufOffset,
111 serialized_manifest.begin(),
112 serialized_manifest.end());
113
114 // Updates the protobuf size.
115 uint64_t size_be = htobe64(serialized_manifest.size());
116 memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
117 LOG(INFO) << "Updated payload size: " << payload.size();
118 out_payload->swap(payload);
119 return true;
120}
121} // namespace {}
122
Jay Srinivasanf4318702012-09-24 11:56:24 -0700123bool PayloadSigner::LoadPayload(const string& payload_path,
124 vector<char>* out_payload,
125 DeltaArchiveManifest* out_manifest,
126 uint64_t* out_metadata_size) {
127 vector<char> payload;
128 // Loads the payload and parses the manifest.
129 TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
130 LOG(INFO) << "Payload size: " << payload.size();
131 ActionExitCode error = kActionCodeSuccess;
132 InstallPlan install_plan;
Jay Srinivasanf0572052012-10-23 18:12:56 -0700133 DeltaPerformer delta_performer(NULL, NULL, &install_plan);
Jay Srinivasanf4318702012-09-24 11:56:24 -0700134 TEST_AND_RETURN_FALSE(delta_performer.ParsePayloadMetadata(
135 payload, out_manifest, out_metadata_size, &error) ==
136 DeltaPerformer::kMetadataParseSuccess);
137 LOG(INFO) << "Metadata size: " << *out_metadata_size;
138 out_payload->swap(payload);
139 return true;
140}
141
Darin Petkov9574f7e2011-01-13 10:48:12 -0800142bool PayloadSigner::SignHash(const vector<char>& hash,
143 const string& private_key_path,
144 vector<char>* out_signature) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700145 LOG(INFO) << "Signing hash with private key: " << private_key_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700146 string sig_path;
147 TEST_AND_RETURN_FALSE(
148 utils::MakeTempFile("/tmp/signature.XXXXXX", &sig_path, NULL));
149 ScopedPathUnlinker sig_path_unlinker(sig_path);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700150
151 string hash_path;
152 TEST_AND_RETURN_FALSE(
153 utils::MakeTempFile("/tmp/hash.XXXXXX", &hash_path, NULL));
154 ScopedPathUnlinker hash_path_unlinker(hash_path);
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700155 // We expect unpadded SHA256 hash coming in
156 TEST_AND_RETURN_FALSE(hash.size() == 32);
157 vector<char> padded_hash(hash);
158 PadRSA2048SHA256Hash(&padded_hash);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700159 TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700160 padded_hash.data(),
161 padded_hash.size()));
Darin Petkovd22cb292010-09-29 10:02:29 -0700162
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700163 // This runs on the server, so it's okay to cop out and call openssl
164 // executable rather than properly use the library
165 vector<string> cmd;
Mike Frysinger2149be42012-03-12 19:23:47 -0400166 base::SplitString("openssl rsautl -raw -sign -inkey x -in x -out x",
Chris Masoned903c3b2011-05-12 15:35:46 -0700167 ' ',
168 &cmd);
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700169 cmd[cmd.size() - 5] = private_key_path;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700170 cmd[cmd.size() - 3] = hash_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700171 cmd[cmd.size() - 1] = sig_path;
Darin Petkovd22cb292010-09-29 10:02:29 -0700172
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700173 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700174 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700175 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700176
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700177 vector<char> signature;
178 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800179 out_signature->swap(signature);
180 return true;
181}
Darin Petkovd22cb292010-09-29 10:02:29 -0700182
Darin Petkov9574f7e2011-01-13 10:48:12 -0800183bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700184 const vector<string>& private_key_paths,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800185 vector<char>* out_signature_blob) {
186 vector<char> hash_data;
187 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
188 unsigned_payload_path, -1, &hash_data) ==
189 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700190
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700191 vector<vector<char> > signatures;
192 for (vector<string>::const_iterator it = private_key_paths.begin(),
193 e = private_key_paths.end(); it != e; ++it) {
194 vector<char> signature;
195 TEST_AND_RETURN_FALSE(SignHash(hash_data, *it, &signature));
196 signatures.push_back(signature);
197 }
198 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800199 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700200 return true;
201}
202
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700203bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
204 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700205 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700206
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700207 string x_path;
208 TEST_AND_RETURN_FALSE(
209 utils::MakeTempFile("/tmp/signed_data.XXXXXX", &x_path, NULL));
210 ScopedPathUnlinker x_path_unlinker(x_path);
211 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
212
213 vector<char> sig_blob;
214 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700215 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700216 &sig_blob));
217 *out_length = sig_blob.size();
218 return true;
219}
220
Darin Petkovd7061ab2010-10-06 14:37:09 -0700221bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
222 const std::string& public_key_path,
223 std::vector<char>* out_hash_data) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700224 return VerifySignatureBlob(signature_blob, public_key_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700225 kSignatureMessageCurrentVersion, out_hash_data);
226}
227
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700228bool PayloadSigner::VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700229 const std::vector<char>& signature_blob,
230 const std::string& public_key_path,
231 uint32_t client_version,
232 std::vector<char>* out_hash_data) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700233 TEST_AND_RETURN_FALSE(!public_key_path.empty());
234
235 Signatures signatures;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700236 LOG(INFO) << "signature size = " << signature_blob.size();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700237 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
238 signature_blob.size()));
239
240 // Finds a signature that matches the current version.
241 int sig_index = 0;
242 for (; sig_index < signatures.signatures_size(); sig_index++) {
243 const Signatures_Signature& signature = signatures.signatures(sig_index);
244 if (signature.has_version() &&
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700245 signature.version() == client_version) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700246 break;
247 }
248 }
249 TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
250
251 const Signatures_Signature& signature = signatures.signatures(sig_index);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700252 vector<char> sig_data(signature.data().begin(), signature.data().end());
253
254 return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
255}
256
257
258bool PayloadSigner::GetRawHashFromSignature(
259 const std::vector<char>& sig_data,
260 const std::string& public_key_path,
261 std::vector<char>* out_hash_data) {
262 TEST_AND_RETURN_FALSE(!public_key_path.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700263
Darin Petkovb039d502010-12-03 09:08:04 -0800264 // The code below executes the equivalent of:
265 //
266 // openssl rsautl -verify -pubin -inkey |public_key_path|
267 // -in |sig_data| -out |out_hash_data|
Darin Petkovd7061ab2010-10-06 14:37:09 -0700268
Darin Petkovb039d502010-12-03 09:08:04 -0800269 // Loads the public key.
270 FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700271 if (!fpubkey) {
272 LOG(ERROR) << "Unable to open public key file: " << public_key_path;
273 return false;
274 }
275
Darin Petkovb039d502010-12-03 09:08:04 -0800276 char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
277 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
278 fclose(fpubkey);
279 TEST_AND_RETURN_FALSE(rsa != NULL);
280 unsigned int keysize = RSA_size(rsa);
281 if (sig_data.size() > 2 * keysize) {
282 LOG(ERROR) << "Signature size is too big for public key size.";
283 RSA_free(rsa);
284 return false;
285 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700286
Darin Petkovb039d502010-12-03 09:08:04 -0800287 // Decrypts the signature.
288 vector<char> hash_data(keysize);
289 int decrypt_size = RSA_public_decrypt(
290 sig_data.size(),
291 reinterpret_cast<const unsigned char*>(sig_data.data()),
292 reinterpret_cast<unsigned char*>(hash_data.data()),
293 rsa,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700294 RSA_NO_PADDING);
Darin Petkovb039d502010-12-03 09:08:04 -0800295 RSA_free(rsa);
296 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
297 decrypt_size <= static_cast<int>(hash_data.size()));
298 hash_data.resize(decrypt_size);
299 out_hash_data->swap(hash_data);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700300 return true;
301}
302
Darin Petkovadb3cef2011-01-13 16:16:08 -0800303bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700304 const std::string& public_key_path,
305 uint32_t client_key_check_version) {
Darin Petkovadb3cef2011-01-13 16:16:08 -0800306 vector<char> payload;
307 DeltaArchiveManifest manifest;
308 uint64_t metadata_size;
309 TEST_AND_RETURN_FALSE(LoadPayload(
310 payload_path, &payload, &manifest, &metadata_size));
311 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
312 manifest.has_signatures_size());
313 CHECK_EQ(payload.size(),
314 metadata_size + manifest.signatures_offset() +
315 manifest.signatures_size());
316 vector<char> signature_blob(
317 payload.begin() + metadata_size + manifest.signatures_offset(),
318 payload.end());
319 vector<char> signed_hash;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700320 TEST_AND_RETURN_FALSE(VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700321 signature_blob, public_key_path, client_key_check_version, &signed_hash));
Darin Petkovadb3cef2011-01-13 16:16:08 -0800322 TEST_AND_RETURN_FALSE(!signed_hash.empty());
323 vector<char> hash;
324 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
325 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700326 PadRSA2048SHA256Hash(&hash);
Darin Petkovadb3cef2011-01-13 16:16:08 -0800327 TEST_AND_RETURN_FALSE(hash == signed_hash);
328 return true;
329}
330
Jay Srinivasanf4318702012-09-24 11:56:24 -0700331bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700332 const vector<int>& signature_sizes,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800333 vector<char>* out_hash_data) {
334 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
335
336 // Loads the payload and adds the signature op to it.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700337 vector<vector<char> > signatures;
338 for (vector<int>::const_iterator it = signature_sizes.begin(),
339 e = signature_sizes.end(); it != e; ++it) {
340 vector<char> signature(*it, 0);
341 signatures.push_back(signature);
342 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800343 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700344 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800345 &signature_blob));
346 vector<char> payload;
347 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
348 signature_blob.size(),
349 &payload));
350 // Calculates the hash on the updated payload. Note that the payload includes
351 // the signature op but doesn't include the signature blob at the end.
352 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfData(payload,
353 out_hash_data));
354 return true;
355}
356
Jay Srinivasanf4318702012-09-24 11:56:24 -0700357bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
358 vector<char>* out_metadata_hash) {
359 // Extract the manifest first.
360 vector<char> payload;
361 DeltaArchiveManifest manifest_proto;
362 uint64_t metadata_size;
363 TEST_AND_RETURN_FALSE(LoadPayload(
364 payload_path, &payload, &manifest_proto, &metadata_size));
365
366 // Calculates the hash on the manifest.
367 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
368 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,
375 const vector<vector<char> >& signatures,
376 const string& signed_payload_path) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800377 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
378
379 // Loads the payload and adds the signature op to it.
380 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700381 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800382 &signature_blob));
383 vector<char> payload;
384 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
385 signature_blob.size(),
386 &payload));
387 // Appends the signature blob to the end of the payload and writes the new
388 // payload.
389 payload.insert(payload.end(), signature_blob.begin(), signature_blob.end());
390 LOG(INFO) << "Signed payload size: " << payload.size();
391 TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
392 payload.data(),
393 payload.size()));
394 return true;
395}
396
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700397bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
398 TEST_AND_RETURN_FALSE(hash->size() == 32);
399 hash->insert(hash->begin(),
Han Shen2643cb72012-06-26 14:45:33 -0700400 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
401 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
402 sizeof(kRSA2048SHA256Padding)));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700403 TEST_AND_RETURN_FALSE(hash->size() == 256);
404 return true;
405}
406
Jay Srinivasanf4318702012-09-24 11:56:24 -0700407bool PayloadSigner::GetMetadataSignature(const char* const metadata,
408 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700409 const string& private_key_path,
410 string* out_signature) {
411 // Calculates the hash on the updated payload. Note that the payload includes
412 // the signature op but doesn't include the signature blob at the end.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700413 vector<char> metadata_hash;
414 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
415 metadata_size,
416 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700417
418 vector<char> signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700419 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700420 private_key_path,
421 &signature));
422
423 TEST_AND_RETURN_FALSE(OmahaHashCalculator::Base64Encode(&signature[0],
424 signature.size(),
425 out_signature));
426 return true;
427}
428
429
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700430} // namespace chromeos_update_engine