blob: 86114b201acf90299f1a6136036bc83495c7dbf8 [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
Gilad Arnold04ba0eb2013-02-11 09:26:00 -080029// The following is a standard PKCS1-v1_5 padding for SHA256 signatures, as
30// defined in RFC3447. It is prepended to the actual signature (32 bytes) to
31// form a sequence of 256 bytes (2048 bits) that is amenable to RSA signing. The
32// padded hash will look as follows:
33//
34// 0x00 0x01 0xff ... 0xff 0x00 ASN1HEADER SHA256HASH
35// |--------------205-----------||----19----||----32----|
36//
37// where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
38// bytes of actual data (i.e. the ASN.1 header complete with the hash) are
39// packed as follows:
40//
41// SEQUENCE(2+49) {
42// SEQUENCE(2+13) {
43// OBJECT(2+9) id-sha256
44// NULL(2+0)
45// }
46// OCTET STRING(2+32) <actual signature bytes...>
47// }
Han Shen2643cb72012-06-26 14:45:33 -070048const unsigned char kRSA2048SHA256Padding[] = {
Gilad Arnold04ba0eb2013-02-11 09:26:00 -080049 // PKCS1-v1_5 padding
50 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
61 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
62 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
69 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
70 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
71 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
72 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
73 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
74 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
75 0xff, 0xff, 0xff, 0xff, 0x00,
76 // ASN.1 header
77 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
78 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
79 0x00, 0x04, 0x20,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -070080};
81
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070082// Given raw |signatures|, packs them into a protobuf and serializes it into a
Darin Petkov9574f7e2011-01-13 10:48:12 -080083// binary blob. Returns true on success, false otherwise.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070084bool ConvertSignatureToProtobufBlob(const vector<vector<char> >& signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -080085 vector<char>* out_signature_blob) {
86 // Pack it into a protobuf
87 Signatures out_message;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070088 uint32_t version = kSignatureMessageOriginalVersion;
89 LOG_IF(WARNING, kSignatureMessageCurrentVersion -
90 kSignatureMessageOriginalVersion + 1 < signatures.size())
Jay Srinivasan51dcf262012-09-13 17:24:32 -070091 << "You may want to support clients in the range ["
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -070092 << kSignatureMessageOriginalVersion << ", "
93 << kSignatureMessageCurrentVersion << "] inclusive, but you only "
94 << "provided " << signatures.size() << " signatures.";
95 for (vector<vector<char> >::const_iterator it = signatures.begin(),
96 e = signatures.end(); it != e; ++it) {
97 const vector<char>& signature = *it;
98 Signatures_Signature* sig_message = out_message.add_signatures();
99 sig_message->set_version(version++);
100 sig_message->set_data(signature.data(), signature.size());
101 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800102
103 // Serialize protobuf
104 string serialized;
105 TEST_AND_RETURN_FALSE(out_message.AppendToString(&serialized));
106 out_signature_blob->insert(out_signature_blob->end(),
107 serialized.begin(),
108 serialized.end());
109 LOG(INFO) << "Signature blob size: " << out_signature_blob->size();
110 return true;
111}
112
113// Given an unsigned payload under |payload_path| and the |signature_blob_size|
114// generates an updated payload that includes a dummy signature op in its
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800115// manifest. It populates |out_metadata_size| with the size of the final
116// manifest after adding the dummy signature operation. Returns true on
117// success, false otherwise.
Darin Petkovadb3cef2011-01-13 16:16:08 -0800118bool AddSignatureOpToPayload(const string& payload_path,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800119 int signature_blob_size,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800120 vector<char>* out_payload,
121 uint64_t* out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800122 const int kProtobufOffset = 20;
123 const int kProtobufSizeOffset = 12;
124
Darin Petkovadb3cef2011-01-13 16:16:08 -0800125 // Loads the payload.
Darin Petkov9574f7e2011-01-13 10:48:12 -0800126 vector<char> payload;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800127 DeltaArchiveManifest manifest;
Darin Petkovadb3cef2011-01-13 16:16:08 -0800128 uint64_t metadata_size;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700129 TEST_AND_RETURN_FALSE(PayloadSigner::LoadPayload(
Darin Petkovadb3cef2011-01-13 16:16:08 -0800130 payload_path, &payload, &manifest, &metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800131 TEST_AND_RETURN_FALSE(!manifest.has_signatures_offset() &&
132 !manifest.has_signatures_size());
133
134 // Updates the manifest to include the signature operation.
135 DeltaDiffGenerator::AddSignatureOp(payload.size() - metadata_size,
136 signature_blob_size,
137 &manifest);
138
139 // Updates the payload to include the new manifest.
140 string serialized_manifest;
141 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
142 LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
143 payload.erase(payload.begin() + kProtobufOffset,
144 payload.begin() + metadata_size);
145 payload.insert(payload.begin() + kProtobufOffset,
146 serialized_manifest.begin(),
147 serialized_manifest.end());
148
149 // Updates the protobuf size.
150 uint64_t size_be = htobe64(serialized_manifest.size());
151 memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
152 LOG(INFO) << "Updated payload size: " << payload.size();
153 out_payload->swap(payload);
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800154 *out_metadata_size = serialized_manifest.size() + kProtobufOffset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800155 return true;
156}
157} // namespace {}
158
Jay Srinivasanf4318702012-09-24 11:56:24 -0700159bool PayloadSigner::LoadPayload(const string& payload_path,
160 vector<char>* out_payload,
161 DeltaArchiveManifest* out_manifest,
162 uint64_t* out_metadata_size) {
163 vector<char> payload;
164 // Loads the payload and parses the manifest.
165 TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
166 LOG(INFO) << "Payload size: " << payload.size();
David Zeuthena99981f2013-04-29 13:42:47 -0700167 ErrorCode error = kErrorCodeSuccess;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700168 InstallPlan install_plan;
Jay Srinivasanf0572052012-10-23 18:12:56 -0700169 DeltaPerformer delta_performer(NULL, NULL, &install_plan);
Jay Srinivasanf4318702012-09-24 11:56:24 -0700170 TEST_AND_RETURN_FALSE(delta_performer.ParsePayloadMetadata(
171 payload, out_manifest, out_metadata_size, &error) ==
172 DeltaPerformer::kMetadataParseSuccess);
173 LOG(INFO) << "Metadata size: " << *out_metadata_size;
174 out_payload->swap(payload);
175 return true;
176}
177
Darin Petkov9574f7e2011-01-13 10:48:12 -0800178bool PayloadSigner::SignHash(const vector<char>& hash,
179 const string& private_key_path,
180 vector<char>* out_signature) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700181 LOG(INFO) << "Signing hash with private key: " << private_key_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700182 string sig_path;
183 TEST_AND_RETURN_FALSE(
184 utils::MakeTempFile("/tmp/signature.XXXXXX", &sig_path, NULL));
185 ScopedPathUnlinker sig_path_unlinker(sig_path);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700186
187 string hash_path;
188 TEST_AND_RETURN_FALSE(
189 utils::MakeTempFile("/tmp/hash.XXXXXX", &hash_path, NULL));
190 ScopedPathUnlinker hash_path_unlinker(hash_path);
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700191 // We expect unpadded SHA256 hash coming in
192 TEST_AND_RETURN_FALSE(hash.size() == 32);
193 vector<char> padded_hash(hash);
194 PadRSA2048SHA256Hash(&padded_hash);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700195 TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700196 padded_hash.data(),
197 padded_hash.size()));
Darin Petkovd22cb292010-09-29 10:02:29 -0700198
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700199 // This runs on the server, so it's okay to cop out and call openssl
200 // executable rather than properly use the library
201 vector<string> cmd;
Mike Frysinger2149be42012-03-12 19:23:47 -0400202 base::SplitString("openssl rsautl -raw -sign -inkey x -in x -out x",
Chris Masoned903c3b2011-05-12 15:35:46 -0700203 ' ',
204 &cmd);
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700205 cmd[cmd.size() - 5] = private_key_path;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700206 cmd[cmd.size() - 3] = hash_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700207 cmd[cmd.size() - 1] = sig_path;
Darin Petkovd22cb292010-09-29 10:02:29 -0700208
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700209 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700210 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700211 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700212
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700213 vector<char> signature;
214 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800215 out_signature->swap(signature);
216 return true;
217}
Darin Petkovd22cb292010-09-29 10:02:29 -0700218
Darin Petkov9574f7e2011-01-13 10:48:12 -0800219bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700220 const vector<string>& private_key_paths,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800221 vector<char>* out_signature_blob) {
222 vector<char> hash_data;
223 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
224 unsigned_payload_path, -1, &hash_data) ==
225 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700226
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700227 vector<vector<char> > signatures;
228 for (vector<string>::const_iterator it = private_key_paths.begin(),
229 e = private_key_paths.end(); it != e; ++it) {
230 vector<char> signature;
231 TEST_AND_RETURN_FALSE(SignHash(hash_data, *it, &signature));
232 signatures.push_back(signature);
233 }
234 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800235 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700236 return true;
237}
238
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700239bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
240 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700241 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700242
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700243 string x_path;
244 TEST_AND_RETURN_FALSE(
245 utils::MakeTempFile("/tmp/signed_data.XXXXXX", &x_path, NULL));
246 ScopedPathUnlinker x_path_unlinker(x_path);
247 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
248
249 vector<char> sig_blob;
250 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700251 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700252 &sig_blob));
253 *out_length = sig_blob.size();
254 return true;
255}
256
Darin Petkovd7061ab2010-10-06 14:37:09 -0700257bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
258 const std::string& public_key_path,
259 std::vector<char>* out_hash_data) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700260 return VerifySignatureBlob(signature_blob, public_key_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700261 kSignatureMessageCurrentVersion, out_hash_data);
262}
263
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700264bool PayloadSigner::VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700265 const std::vector<char>& signature_blob,
266 const std::string& public_key_path,
267 uint32_t client_version,
268 std::vector<char>* out_hash_data) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700269 TEST_AND_RETURN_FALSE(!public_key_path.empty());
270
271 Signatures signatures;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700272 LOG(INFO) << "signature size = " << signature_blob.size();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700273 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
274 signature_blob.size()));
275
276 // Finds a signature that matches the current version.
277 int sig_index = 0;
278 for (; sig_index < signatures.signatures_size(); sig_index++) {
279 const Signatures_Signature& signature = signatures.signatures(sig_index);
280 if (signature.has_version() &&
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700281 signature.version() == client_version) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700282 break;
283 }
284 }
285 TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
286
287 const Signatures_Signature& signature = signatures.signatures(sig_index);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700288 vector<char> sig_data(signature.data().begin(), signature.data().end());
289
290 return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
291}
292
293
294bool PayloadSigner::GetRawHashFromSignature(
295 const std::vector<char>& sig_data,
296 const std::string& public_key_path,
297 std::vector<char>* out_hash_data) {
298 TEST_AND_RETURN_FALSE(!public_key_path.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700299
Darin Petkovb039d502010-12-03 09:08:04 -0800300 // The code below executes the equivalent of:
301 //
302 // openssl rsautl -verify -pubin -inkey |public_key_path|
303 // -in |sig_data| -out |out_hash_data|
Darin Petkovd7061ab2010-10-06 14:37:09 -0700304
Darin Petkovb039d502010-12-03 09:08:04 -0800305 // Loads the public key.
306 FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700307 if (!fpubkey) {
308 LOG(ERROR) << "Unable to open public key file: " << public_key_path;
309 return false;
310 }
311
Darin Petkovb039d502010-12-03 09:08:04 -0800312 char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
313 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
314 fclose(fpubkey);
315 TEST_AND_RETURN_FALSE(rsa != NULL);
316 unsigned int keysize = RSA_size(rsa);
317 if (sig_data.size() > 2 * keysize) {
318 LOG(ERROR) << "Signature size is too big for public key size.";
319 RSA_free(rsa);
320 return false;
321 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700322
Darin Petkovb039d502010-12-03 09:08:04 -0800323 // Decrypts the signature.
324 vector<char> hash_data(keysize);
325 int decrypt_size = RSA_public_decrypt(
326 sig_data.size(),
327 reinterpret_cast<const unsigned char*>(sig_data.data()),
328 reinterpret_cast<unsigned char*>(hash_data.data()),
329 rsa,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700330 RSA_NO_PADDING);
Darin Petkovb039d502010-12-03 09:08:04 -0800331 RSA_free(rsa);
332 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
333 decrypt_size <= static_cast<int>(hash_data.size()));
334 hash_data.resize(decrypt_size);
335 out_hash_data->swap(hash_data);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700336 return true;
337}
338
Darin Petkovadb3cef2011-01-13 16:16:08 -0800339bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700340 const std::string& public_key_path,
341 uint32_t client_key_check_version) {
Darin Petkovadb3cef2011-01-13 16:16:08 -0800342 vector<char> payload;
343 DeltaArchiveManifest manifest;
344 uint64_t metadata_size;
345 TEST_AND_RETURN_FALSE(LoadPayload(
346 payload_path, &payload, &manifest, &metadata_size));
347 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
348 manifest.has_signatures_size());
349 CHECK_EQ(payload.size(),
350 metadata_size + manifest.signatures_offset() +
351 manifest.signatures_size());
352 vector<char> signature_blob(
353 payload.begin() + metadata_size + manifest.signatures_offset(),
354 payload.end());
355 vector<char> signed_hash;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700356 TEST_AND_RETURN_FALSE(VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700357 signature_blob, public_key_path, client_key_check_version, &signed_hash));
Darin Petkovadb3cef2011-01-13 16:16:08 -0800358 TEST_AND_RETURN_FALSE(!signed_hash.empty());
359 vector<char> hash;
360 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
361 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700362 PadRSA2048SHA256Hash(&hash);
Darin Petkovadb3cef2011-01-13 16:16:08 -0800363 TEST_AND_RETURN_FALSE(hash == signed_hash);
364 return true;
365}
366
Jay Srinivasanf4318702012-09-24 11:56:24 -0700367bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700368 const vector<int>& signature_sizes,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800369 vector<char>* out_hash_data) {
370 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
371
372 // Loads the payload and adds the signature op to it.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700373 vector<vector<char> > signatures;
374 for (vector<int>::const_iterator it = signature_sizes.begin(),
375 e = signature_sizes.end(); it != e; ++it) {
376 vector<char> signature(*it, 0);
377 signatures.push_back(signature);
378 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800379 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700380 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800381 &signature_blob));
382 vector<char> payload;
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800383 uint64_t final_metadata_size;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800384 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
385 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800386 &payload,
387 &final_metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800388 // Calculates the hash on the updated payload. Note that the payload includes
389 // the signature op but doesn't include the signature blob at the end.
390 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfData(payload,
391 out_hash_data));
392 return true;
393}
394
Jay Srinivasanf4318702012-09-24 11:56:24 -0700395bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
396 vector<char>* out_metadata_hash) {
397 // Extract the manifest first.
398 vector<char> payload;
399 DeltaArchiveManifest manifest_proto;
400 uint64_t metadata_size;
401 TEST_AND_RETURN_FALSE(LoadPayload(
402 payload_path, &payload, &manifest_proto, &metadata_size));
403
404 // Calculates the hash on the manifest.
405 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
406 metadata_size,
407 out_metadata_hash));
408 return true;
409}
410
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700411bool PayloadSigner::AddSignatureToPayload(
412 const string& payload_path,
413 const vector<vector<char> >& signatures,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800414 const string& signed_payload_path,
415 uint64_t *out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800416 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
417
418 // Loads the payload and adds the signature op to it.
419 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700420 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800421 &signature_blob));
422 vector<char> payload;
423 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
424 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800425 &payload,
426 out_metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800427 // Appends the signature blob to the end of the payload and writes the new
428 // payload.
429 payload.insert(payload.end(), signature_blob.begin(), signature_blob.end());
430 LOG(INFO) << "Signed payload size: " << payload.size();
431 TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
432 payload.data(),
433 payload.size()));
434 return true;
435}
436
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700437bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
438 TEST_AND_RETURN_FALSE(hash->size() == 32);
439 hash->insert(hash->begin(),
Han Shen2643cb72012-06-26 14:45:33 -0700440 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
441 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
442 sizeof(kRSA2048SHA256Padding)));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700443 TEST_AND_RETURN_FALSE(hash->size() == 256);
444 return true;
445}
446
Jay Srinivasanf4318702012-09-24 11:56:24 -0700447bool PayloadSigner::GetMetadataSignature(const char* const metadata,
448 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700449 const string& private_key_path,
450 string* out_signature) {
451 // Calculates the hash on the updated payload. Note that the payload includes
452 // the signature op but doesn't include the signature blob at the end.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700453 vector<char> metadata_hash;
454 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
455 metadata_size,
456 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700457
458 vector<char> signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700459 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700460 private_key_path,
461 &signature));
462
463 TEST_AND_RETURN_FALSE(OmahaHashCalculator::Base64Encode(&signature[0],
464 signature.size(),
465 out_signature));
466 return true;
467}
468
469
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700470} // namespace chromeos_update_engine