blob: ff60949d3b94b350ff503c0289f2294a28215528 [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
Jay Srinivasan738fdf32012-12-07 17:40:54 -080083// manifest. It populates |out_metadata_size| with the size of the final
84// manifest after adding the dummy signature operation. Returns true on
85// success, false otherwise.
Darin Petkovadb3cef2011-01-13 16:16:08 -080086bool AddSignatureOpToPayload(const string& payload_path,
Darin Petkov9574f7e2011-01-13 10:48:12 -080087 int signature_blob_size,
Jay Srinivasan738fdf32012-12-07 17:40:54 -080088 vector<char>* out_payload,
89 uint64_t* out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -080090 const int kProtobufOffset = 20;
91 const int kProtobufSizeOffset = 12;
92
Darin Petkovadb3cef2011-01-13 16:16:08 -080093 // Loads the payload.
Darin Petkov9574f7e2011-01-13 10:48:12 -080094 vector<char> payload;
Darin Petkov9574f7e2011-01-13 10:48:12 -080095 DeltaArchiveManifest manifest;
Darin Petkovadb3cef2011-01-13 16:16:08 -080096 uint64_t metadata_size;
Jay Srinivasanf4318702012-09-24 11:56:24 -070097 TEST_AND_RETURN_FALSE(PayloadSigner::LoadPayload(
Darin Petkovadb3cef2011-01-13 16:16:08 -080098 payload_path, &payload, &manifest, &metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -080099 TEST_AND_RETURN_FALSE(!manifest.has_signatures_offset() &&
100 !manifest.has_signatures_size());
101
102 // Updates the manifest to include the signature operation.
103 DeltaDiffGenerator::AddSignatureOp(payload.size() - metadata_size,
104 signature_blob_size,
105 &manifest);
106
107 // Updates the payload to include the new manifest.
108 string serialized_manifest;
109 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
110 LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
111 payload.erase(payload.begin() + kProtobufOffset,
112 payload.begin() + metadata_size);
113 payload.insert(payload.begin() + kProtobufOffset,
114 serialized_manifest.begin(),
115 serialized_manifest.end());
116
117 // Updates the protobuf size.
118 uint64_t size_be = htobe64(serialized_manifest.size());
119 memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
120 LOG(INFO) << "Updated payload size: " << payload.size();
121 out_payload->swap(payload);
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800122 *out_metadata_size = serialized_manifest.size() + kProtobufOffset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800123 return true;
124}
125} // namespace {}
126
Jay Srinivasanf4318702012-09-24 11:56:24 -0700127bool PayloadSigner::LoadPayload(const string& payload_path,
128 vector<char>* out_payload,
129 DeltaArchiveManifest* out_manifest,
130 uint64_t* out_metadata_size) {
131 vector<char> payload;
132 // Loads the payload and parses the manifest.
133 TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
134 LOG(INFO) << "Payload size: " << payload.size();
135 ActionExitCode error = kActionCodeSuccess;
136 InstallPlan install_plan;
Jay Srinivasanf0572052012-10-23 18:12:56 -0700137 DeltaPerformer delta_performer(NULL, NULL, &install_plan);
Jay Srinivasanf4318702012-09-24 11:56:24 -0700138 TEST_AND_RETURN_FALSE(delta_performer.ParsePayloadMetadata(
139 payload, out_manifest, out_metadata_size, &error) ==
140 DeltaPerformer::kMetadataParseSuccess);
141 LOG(INFO) << "Metadata size: " << *out_metadata_size;
142 out_payload->swap(payload);
143 return true;
144}
145
Darin Petkov9574f7e2011-01-13 10:48:12 -0800146bool PayloadSigner::SignHash(const vector<char>& hash,
147 const string& private_key_path,
148 vector<char>* out_signature) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700149 LOG(INFO) << "Signing hash with private key: " << private_key_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700150 string sig_path;
151 TEST_AND_RETURN_FALSE(
152 utils::MakeTempFile("/tmp/signature.XXXXXX", &sig_path, NULL));
153 ScopedPathUnlinker sig_path_unlinker(sig_path);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700154
155 string hash_path;
156 TEST_AND_RETURN_FALSE(
157 utils::MakeTempFile("/tmp/hash.XXXXXX", &hash_path, NULL));
158 ScopedPathUnlinker hash_path_unlinker(hash_path);
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700159 // We expect unpadded SHA256 hash coming in
160 TEST_AND_RETURN_FALSE(hash.size() == 32);
161 vector<char> padded_hash(hash);
162 PadRSA2048SHA256Hash(&padded_hash);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700163 TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700164 padded_hash.data(),
165 padded_hash.size()));
Darin Petkovd22cb292010-09-29 10:02:29 -0700166
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700167 // This runs on the server, so it's okay to cop out and call openssl
168 // executable rather than properly use the library
169 vector<string> cmd;
Mike Frysinger2149be42012-03-12 19:23:47 -0400170 base::SplitString("openssl rsautl -raw -sign -inkey x -in x -out x",
Chris Masoned903c3b2011-05-12 15:35:46 -0700171 ' ',
172 &cmd);
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700173 cmd[cmd.size() - 5] = private_key_path;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700174 cmd[cmd.size() - 3] = hash_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700175 cmd[cmd.size() - 1] = sig_path;
Darin Petkovd22cb292010-09-29 10:02:29 -0700176
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700177 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700178 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700179 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700180
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700181 vector<char> signature;
182 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800183 out_signature->swap(signature);
184 return true;
185}
Darin Petkovd22cb292010-09-29 10:02:29 -0700186
Darin Petkov9574f7e2011-01-13 10:48:12 -0800187bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700188 const vector<string>& private_key_paths,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800189 vector<char>* out_signature_blob) {
190 vector<char> hash_data;
191 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
192 unsigned_payload_path, -1, &hash_data) ==
193 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700194
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700195 vector<vector<char> > signatures;
196 for (vector<string>::const_iterator it = private_key_paths.begin(),
197 e = private_key_paths.end(); it != e; ++it) {
198 vector<char> signature;
199 TEST_AND_RETURN_FALSE(SignHash(hash_data, *it, &signature));
200 signatures.push_back(signature);
201 }
202 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800203 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700204 return true;
205}
206
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700207bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
208 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700209 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700210
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700211 string x_path;
212 TEST_AND_RETURN_FALSE(
213 utils::MakeTempFile("/tmp/signed_data.XXXXXX", &x_path, NULL));
214 ScopedPathUnlinker x_path_unlinker(x_path);
215 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
216
217 vector<char> sig_blob;
218 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700219 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700220 &sig_blob));
221 *out_length = sig_blob.size();
222 return true;
223}
224
Darin Petkovd7061ab2010-10-06 14:37:09 -0700225bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
226 const std::string& public_key_path,
227 std::vector<char>* out_hash_data) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700228 return VerifySignatureBlob(signature_blob, public_key_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700229 kSignatureMessageCurrentVersion, out_hash_data);
230}
231
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700232bool PayloadSigner::VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700233 const std::vector<char>& signature_blob,
234 const std::string& public_key_path,
235 uint32_t client_version,
236 std::vector<char>* out_hash_data) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700237 TEST_AND_RETURN_FALSE(!public_key_path.empty());
238
239 Signatures signatures;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700240 LOG(INFO) << "signature size = " << signature_blob.size();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700241 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
242 signature_blob.size()));
243
244 // Finds a signature that matches the current version.
245 int sig_index = 0;
246 for (; sig_index < signatures.signatures_size(); sig_index++) {
247 const Signatures_Signature& signature = signatures.signatures(sig_index);
248 if (signature.has_version() &&
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700249 signature.version() == client_version) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700250 break;
251 }
252 }
253 TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
254
255 const Signatures_Signature& signature = signatures.signatures(sig_index);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700256 vector<char> sig_data(signature.data().begin(), signature.data().end());
257
258 return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
259}
260
261
262bool PayloadSigner::GetRawHashFromSignature(
263 const std::vector<char>& sig_data,
264 const std::string& public_key_path,
265 std::vector<char>* out_hash_data) {
266 TEST_AND_RETURN_FALSE(!public_key_path.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700267
Darin Petkovb039d502010-12-03 09:08:04 -0800268 // The code below executes the equivalent of:
269 //
270 // openssl rsautl -verify -pubin -inkey |public_key_path|
271 // -in |sig_data| -out |out_hash_data|
Darin Petkovd7061ab2010-10-06 14:37:09 -0700272
Darin Petkovb039d502010-12-03 09:08:04 -0800273 // Loads the public key.
274 FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700275 if (!fpubkey) {
276 LOG(ERROR) << "Unable to open public key file: " << public_key_path;
277 return false;
278 }
279
Darin Petkovb039d502010-12-03 09:08:04 -0800280 char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
281 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
282 fclose(fpubkey);
283 TEST_AND_RETURN_FALSE(rsa != NULL);
284 unsigned int keysize = RSA_size(rsa);
285 if (sig_data.size() > 2 * keysize) {
286 LOG(ERROR) << "Signature size is too big for public key size.";
287 RSA_free(rsa);
288 return false;
289 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700290
Darin Petkovb039d502010-12-03 09:08:04 -0800291 // Decrypts the signature.
292 vector<char> hash_data(keysize);
293 int decrypt_size = RSA_public_decrypt(
294 sig_data.size(),
295 reinterpret_cast<const unsigned char*>(sig_data.data()),
296 reinterpret_cast<unsigned char*>(hash_data.data()),
297 rsa,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700298 RSA_NO_PADDING);
Darin Petkovb039d502010-12-03 09:08:04 -0800299 RSA_free(rsa);
300 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
301 decrypt_size <= static_cast<int>(hash_data.size()));
302 hash_data.resize(decrypt_size);
303 out_hash_data->swap(hash_data);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700304 return true;
305}
306
Darin Petkovadb3cef2011-01-13 16:16:08 -0800307bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700308 const std::string& public_key_path,
309 uint32_t client_key_check_version) {
Darin Petkovadb3cef2011-01-13 16:16:08 -0800310 vector<char> payload;
311 DeltaArchiveManifest manifest;
312 uint64_t metadata_size;
313 TEST_AND_RETURN_FALSE(LoadPayload(
314 payload_path, &payload, &manifest, &metadata_size));
315 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
316 manifest.has_signatures_size());
317 CHECK_EQ(payload.size(),
318 metadata_size + manifest.signatures_offset() +
319 manifest.signatures_size());
320 vector<char> signature_blob(
321 payload.begin() + metadata_size + manifest.signatures_offset(),
322 payload.end());
323 vector<char> signed_hash;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700324 TEST_AND_RETURN_FALSE(VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700325 signature_blob, public_key_path, client_key_check_version, &signed_hash));
Darin Petkovadb3cef2011-01-13 16:16:08 -0800326 TEST_AND_RETURN_FALSE(!signed_hash.empty());
327 vector<char> hash;
328 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
329 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700330 PadRSA2048SHA256Hash(&hash);
Darin Petkovadb3cef2011-01-13 16:16:08 -0800331 TEST_AND_RETURN_FALSE(hash == signed_hash);
332 return true;
333}
334
Jay Srinivasanf4318702012-09-24 11:56:24 -0700335bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700336 const vector<int>& signature_sizes,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800337 vector<char>* out_hash_data) {
338 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
339
340 // Loads the payload and adds the signature op to it.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700341 vector<vector<char> > signatures;
342 for (vector<int>::const_iterator it = signature_sizes.begin(),
343 e = signature_sizes.end(); it != e; ++it) {
344 vector<char> signature(*it, 0);
345 signatures.push_back(signature);
346 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800347 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700348 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800349 &signature_blob));
350 vector<char> payload;
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800351 uint64_t final_metadata_size;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800352 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
353 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800354 &payload,
355 &final_metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800356 // Calculates the hash on the updated payload. Note that the payload includes
357 // the signature op but doesn't include the signature blob at the end.
358 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfData(payload,
359 out_hash_data));
360 return true;
361}
362
Jay Srinivasanf4318702012-09-24 11:56:24 -0700363bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
364 vector<char>* out_metadata_hash) {
365 // Extract the manifest first.
366 vector<char> payload;
367 DeltaArchiveManifest manifest_proto;
368 uint64_t metadata_size;
369 TEST_AND_RETURN_FALSE(LoadPayload(
370 payload_path, &payload, &manifest_proto, &metadata_size));
371
372 // Calculates the hash on the manifest.
373 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
374 metadata_size,
375 out_metadata_hash));
376 return true;
377}
378
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700379bool PayloadSigner::AddSignatureToPayload(
380 const string& payload_path,
381 const vector<vector<char> >& signatures,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800382 const string& signed_payload_path,
383 uint64_t *out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800384 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
385
386 // Loads the payload and adds the signature op to it.
387 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700388 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800389 &signature_blob));
390 vector<char> payload;
391 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
392 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800393 &payload,
394 out_metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800395 // Appends the signature blob to the end of the payload and writes the new
396 // payload.
397 payload.insert(payload.end(), signature_blob.begin(), signature_blob.end());
398 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
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700405bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
406 TEST_AND_RETURN_FALSE(hash->size() == 32);
407 hash->insert(hash->begin(),
Han Shen2643cb72012-06-26 14:45:33 -0700408 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
409 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
410 sizeof(kRSA2048SHA256Padding)));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700411 TEST_AND_RETURN_FALSE(hash->size() == 256);
412 return true;
413}
414
Jay Srinivasanf4318702012-09-24 11:56:24 -0700415bool PayloadSigner::GetMetadataSignature(const char* const metadata,
416 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700417 const string& private_key_path,
418 string* out_signature) {
419 // Calculates the hash on the updated payload. Note that the payload includes
420 // the signature op but doesn't include the signature blob at the end.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700421 vector<char> metadata_hash;
422 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
423 metadata_size,
424 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700425
426 vector<char> signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700427 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700428 private_key_path,
429 &signature));
430
431 TEST_AND_RETURN_FALSE(OmahaHashCalculator::Base64Encode(&signature[0],
432 signature.size(),
433 out_signature));
434 return true;
435}
436
437
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700438} // namespace chromeos_update_engine