blob: c962195b214f0b56285f2d1fd822856f5fd2f650 [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
Don Garrett2ae37872013-10-25 13:33:20 -0700116// manifest after adding the dummy signature operation, and
117// |out_signatures_offset| with the expected offset for the new blob. Returns
118// true on success, false otherwise.
Darin Petkovadb3cef2011-01-13 16:16:08 -0800119bool AddSignatureOpToPayload(const string& payload_path,
Don Garrett2ae37872013-10-25 13:33:20 -0700120 uint64_t signature_blob_size,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800121 vector<char>* out_payload,
Don Garrett2ae37872013-10-25 13:33:20 -0700122 uint64_t* out_metadata_size,
123 uint64_t* out_signatures_offset) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800124 const int kProtobufOffset = 20;
125 const int kProtobufSizeOffset = 12;
126
Darin Petkovadb3cef2011-01-13 16:16:08 -0800127 // Loads the payload.
Darin Petkov9574f7e2011-01-13 10:48:12 -0800128 vector<char> payload;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800129 DeltaArchiveManifest manifest;
Darin Petkovadb3cef2011-01-13 16:16:08 -0800130 uint64_t metadata_size;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700131 TEST_AND_RETURN_FALSE(PayloadSigner::LoadPayload(
Darin Petkovadb3cef2011-01-13 16:16:08 -0800132 payload_path, &payload, &manifest, &metadata_size));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800133
Don Garrett2ae37872013-10-25 13:33:20 -0700134 // Is there already a signature op in place?
135 if (manifest.has_signatures_size()) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800136
Don Garrett2ae37872013-10-25 13:33:20 -0700137 // The signature op is tied to the size of the signature blob, but not it's
138 // contents. We don't allow the manifest to change if there is already an op
139 // present, because that might invalidate previously generated
140 // hashes/signatures.
141 if (manifest.signatures_size() != signature_blob_size) {
142 LOG(ERROR) << "Attempt to insert different signature sized blob. "
143 << "(current:" << manifest.signatures_size()
144 << "new:" << signature_blob_size << ")";
145 return false;
146 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800147
Don Garrett2ae37872013-10-25 13:33:20 -0700148 LOG(INFO) << "Matching signature sizes already present.";
149 } else {
150 // Updates the manifest to include the signature operation.
151 DeltaDiffGenerator::AddSignatureOp(payload.size() - metadata_size,
152 signature_blob_size,
153 &manifest);
154
155 // Updates the payload to include the new manifest.
156 string serialized_manifest;
157 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
158 LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
159 payload.erase(payload.begin() + kProtobufOffset,
160 payload.begin() + metadata_size);
161 payload.insert(payload.begin() + kProtobufOffset,
162 serialized_manifest.begin(),
163 serialized_manifest.end());
164
165 // Updates the protobuf size.
166 uint64_t size_be = htobe64(serialized_manifest.size());
167 memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
168 metadata_size = serialized_manifest.size() + kProtobufOffset;
169
170 LOG(INFO) << "Updated payload size: " << payload.size();
171 LOG(INFO) << "Updated metadata size: " << metadata_size;
172 }
173
Darin Petkov9574f7e2011-01-13 10:48:12 -0800174 out_payload->swap(payload);
Don Garrett2ae37872013-10-25 13:33:20 -0700175 *out_metadata_size = metadata_size;
176 *out_signatures_offset = metadata_size + manifest.signatures_offset();
177 LOG(INFO) << "Signature Blob Offset: " << *out_signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800178 return true;
179}
180} // namespace {}
181
Jay Srinivasanf4318702012-09-24 11:56:24 -0700182bool PayloadSigner::LoadPayload(const string& payload_path,
183 vector<char>* out_payload,
184 DeltaArchiveManifest* out_manifest,
185 uint64_t* out_metadata_size) {
186 vector<char> payload;
187 // Loads the payload and parses the manifest.
188 TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
189 LOG(INFO) << "Payload size: " << payload.size();
David Zeuthena99981f2013-04-29 13:42:47 -0700190 ErrorCode error = kErrorCodeSuccess;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700191 InstallPlan install_plan;
Jay Srinivasanf0572052012-10-23 18:12:56 -0700192 DeltaPerformer delta_performer(NULL, NULL, &install_plan);
Jay Srinivasanf4318702012-09-24 11:56:24 -0700193 TEST_AND_RETURN_FALSE(delta_performer.ParsePayloadMetadata(
194 payload, out_manifest, out_metadata_size, &error) ==
195 DeltaPerformer::kMetadataParseSuccess);
196 LOG(INFO) << "Metadata size: " << *out_metadata_size;
197 out_payload->swap(payload);
198 return true;
199}
200
Darin Petkov9574f7e2011-01-13 10:48:12 -0800201bool PayloadSigner::SignHash(const vector<char>& hash,
202 const string& private_key_path,
203 vector<char>* out_signature) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700204 LOG(INFO) << "Signing hash with private key: " << private_key_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700205 string sig_path;
206 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800207 utils::MakeTempFile("signature.XXXXXX", &sig_path, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700208 ScopedPathUnlinker sig_path_unlinker(sig_path);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700209
210 string hash_path;
211 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800212 utils::MakeTempFile("hash.XXXXXX", &hash_path, NULL));
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700213 ScopedPathUnlinker hash_path_unlinker(hash_path);
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700214 // We expect unpadded SHA256 hash coming in
215 TEST_AND_RETURN_FALSE(hash.size() == 32);
216 vector<char> padded_hash(hash);
217 PadRSA2048SHA256Hash(&padded_hash);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700218 TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700219 padded_hash.data(),
220 padded_hash.size()));
Darin Petkovd22cb292010-09-29 10:02:29 -0700221
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700222 // This runs on the server, so it's okay to cop out and call openssl
223 // executable rather than properly use the library
224 vector<string> cmd;
Mike Frysinger2149be42012-03-12 19:23:47 -0400225 base::SplitString("openssl rsautl -raw -sign -inkey x -in x -out x",
Chris Masoned903c3b2011-05-12 15:35:46 -0700226 ' ',
227 &cmd);
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700228 cmd[cmd.size() - 5] = private_key_path;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700229 cmd[cmd.size() - 3] = hash_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700230 cmd[cmd.size() - 1] = sig_path;
Darin Petkovd22cb292010-09-29 10:02:29 -0700231
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700232 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700233 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700234 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700235
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700236 vector<char> signature;
237 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800238 out_signature->swap(signature);
239 return true;
240}
Darin Petkovd22cb292010-09-29 10:02:29 -0700241
Darin Petkov9574f7e2011-01-13 10:48:12 -0800242bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700243 const vector<string>& private_key_paths,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800244 vector<char>* out_signature_blob) {
245 vector<char> hash_data;
246 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
247 unsigned_payload_path, -1, &hash_data) ==
248 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700249
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700250 vector<vector<char> > signatures;
251 for (vector<string>::const_iterator it = private_key_paths.begin(),
252 e = private_key_paths.end(); it != e; ++it) {
253 vector<char> signature;
254 TEST_AND_RETURN_FALSE(SignHash(hash_data, *it, &signature));
255 signatures.push_back(signature);
256 }
257 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800258 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700259 return true;
260}
261
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700262bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
263 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700264 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700265
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700266 string x_path;
267 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800268 utils::MakeTempFile("signed_data.XXXXXX", &x_path, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700269 ScopedPathUnlinker x_path_unlinker(x_path);
270 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
271
272 vector<char> sig_blob;
273 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700274 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700275 &sig_blob));
276 *out_length = sig_blob.size();
277 return true;
278}
279
Darin Petkovd7061ab2010-10-06 14:37:09 -0700280bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
281 const std::string& public_key_path,
282 std::vector<char>* out_hash_data) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700283 return VerifySignatureBlob(signature_blob, public_key_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700284 kSignatureMessageCurrentVersion, out_hash_data);
285}
286
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700287bool PayloadSigner::VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700288 const std::vector<char>& signature_blob,
289 const std::string& public_key_path,
290 uint32_t client_version,
291 std::vector<char>* out_hash_data) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700292 TEST_AND_RETURN_FALSE(!public_key_path.empty());
293
294 Signatures signatures;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700295 LOG(INFO) << "signature size = " << signature_blob.size();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700296 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
297 signature_blob.size()));
298
299 // Finds a signature that matches the current version.
300 int sig_index = 0;
301 for (; sig_index < signatures.signatures_size(); sig_index++) {
302 const Signatures_Signature& signature = signatures.signatures(sig_index);
303 if (signature.has_version() &&
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700304 signature.version() == client_version) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700305 break;
306 }
307 }
308 TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
309
310 const Signatures_Signature& signature = signatures.signatures(sig_index);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700311 vector<char> sig_data(signature.data().begin(), signature.data().end());
312
313 return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
314}
315
316
317bool PayloadSigner::GetRawHashFromSignature(
318 const std::vector<char>& sig_data,
319 const std::string& public_key_path,
320 std::vector<char>* out_hash_data) {
321 TEST_AND_RETURN_FALSE(!public_key_path.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700322
Darin Petkovb039d502010-12-03 09:08:04 -0800323 // The code below executes the equivalent of:
324 //
325 // openssl rsautl -verify -pubin -inkey |public_key_path|
326 // -in |sig_data| -out |out_hash_data|
Darin Petkovd7061ab2010-10-06 14:37:09 -0700327
Darin Petkovb039d502010-12-03 09:08:04 -0800328 // Loads the public key.
329 FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700330 if (!fpubkey) {
331 LOG(ERROR) << "Unable to open public key file: " << public_key_path;
332 return false;
333 }
334
Darin Petkovb039d502010-12-03 09:08:04 -0800335 char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
336 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
337 fclose(fpubkey);
338 TEST_AND_RETURN_FALSE(rsa != NULL);
339 unsigned int keysize = RSA_size(rsa);
340 if (sig_data.size() > 2 * keysize) {
341 LOG(ERROR) << "Signature size is too big for public key size.";
342 RSA_free(rsa);
343 return false;
344 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700345
Darin Petkovb039d502010-12-03 09:08:04 -0800346 // Decrypts the signature.
347 vector<char> hash_data(keysize);
348 int decrypt_size = RSA_public_decrypt(
349 sig_data.size(),
350 reinterpret_cast<const unsigned char*>(sig_data.data()),
351 reinterpret_cast<unsigned char*>(hash_data.data()),
352 rsa,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700353 RSA_NO_PADDING);
Darin Petkovb039d502010-12-03 09:08:04 -0800354 RSA_free(rsa);
355 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
356 decrypt_size <= static_cast<int>(hash_data.size()));
357 hash_data.resize(decrypt_size);
358 out_hash_data->swap(hash_data);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700359 return true;
360}
361
Darin Petkovadb3cef2011-01-13 16:16:08 -0800362bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700363 const std::string& public_key_path,
364 uint32_t client_key_check_version) {
Darin Petkovadb3cef2011-01-13 16:16:08 -0800365 vector<char> payload;
366 DeltaArchiveManifest manifest;
367 uint64_t metadata_size;
368 TEST_AND_RETURN_FALSE(LoadPayload(
369 payload_path, &payload, &manifest, &metadata_size));
370 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
371 manifest.has_signatures_size());
372 CHECK_EQ(payload.size(),
373 metadata_size + manifest.signatures_offset() +
374 manifest.signatures_size());
375 vector<char> signature_blob(
376 payload.begin() + metadata_size + manifest.signatures_offset(),
377 payload.end());
378 vector<char> signed_hash;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700379 TEST_AND_RETURN_FALSE(VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700380 signature_blob, public_key_path, client_key_check_version, &signed_hash));
Darin Petkovadb3cef2011-01-13 16:16:08 -0800381 TEST_AND_RETURN_FALSE(!signed_hash.empty());
382 vector<char> hash;
383 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
384 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700385 PadRSA2048SHA256Hash(&hash);
Darin Petkovadb3cef2011-01-13 16:16:08 -0800386 TEST_AND_RETURN_FALSE(hash == signed_hash);
387 return true;
388}
389
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700390bool PayloadSigner::PrepPayloadForHashing(
391 const string& payload_path,
392 const vector<int>& signature_sizes,
393 vector<char>* payload_out,
394 uint64_t* metadata_size_out,
395 uint64_t* signatures_offset_out) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800396 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
397
398 // Loads the payload and adds the signature op to it.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700399 vector<vector<char> > signatures;
400 for (vector<int>::const_iterator it = signature_sizes.begin(),
401 e = signature_sizes.end(); it != e; ++it) {
402 vector<char> signature(*it, 0);
403 signatures.push_back(signature);
404 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800405 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700406 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800407 &signature_blob));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800408 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
409 signature_blob.size(),
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700410 payload_out,
411 metadata_size_out,
412 signatures_offset_out));
Don Garrett2ae37872013-10-25 13:33:20 -0700413
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700414 return true;
415}
416
417bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
418 const vector<int>& signature_sizes,
419 vector<char>* out_hash_data) {
420 vector<char> payload;
421 uint64_t metadata_size;
422 uint64_t signatures_offset;
423
424 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
425 signature_sizes,
426 &payload,
427 &metadata_size,
428 &signatures_offset));
Don Garrett2ae37872013-10-25 13:33:20 -0700429
430 // Calculates the hash on the updated payload. Note that we stop calculating
431 // before we reach the signature information.
432 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
433 signatures_offset,
434 out_hash_data));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800435 return true;
436}
437
Jay Srinivasanf4318702012-09-24 11:56:24 -0700438bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700439 const vector<int>& signature_sizes,
Jay Srinivasanf4318702012-09-24 11:56:24 -0700440 vector<char>* out_metadata_hash) {
Jay Srinivasanf4318702012-09-24 11:56:24 -0700441 vector<char> payload;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700442 uint64_t metadata_size;
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700443 uint64_t signatures_offset;
444
445 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
446 signature_sizes,
447 &payload,
448 &metadata_size,
449 &signatures_offset));
Jay Srinivasanf4318702012-09-24 11:56:24 -0700450
451 // Calculates the hash on the manifest.
452 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
453 metadata_size,
454 out_metadata_hash));
455 return true;
456}
457
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700458bool PayloadSigner::AddSignatureToPayload(
459 const string& payload_path,
460 const vector<vector<char> >& signatures,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800461 const string& signed_payload_path,
462 uint64_t *out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800463 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
464
465 // Loads the payload and adds the signature op to it.
466 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700467 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800468 &signature_blob));
469 vector<char> payload;
Don Garrett2ae37872013-10-25 13:33:20 -0700470 uint64_t signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800471 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
472 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800473 &payload,
Don Garrett2ae37872013-10-25 13:33:20 -0700474 out_metadata_size,
475 &signatures_offset));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800476 // Appends the signature blob to the end of the payload and writes the new
477 // payload.
Don Garrett2ae37872013-10-25 13:33:20 -0700478 LOG(INFO) << "Payload size before signatures: " << payload.size();
479 payload.resize(signatures_offset);
480 payload.insert(payload.begin() + signatures_offset,
481 signature_blob.begin(),
482 signature_blob.end());
Darin Petkov9574f7e2011-01-13 10:48:12 -0800483 LOG(INFO) << "Signed payload size: " << payload.size();
484 TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
485 payload.data(),
486 payload.size()));
487 return true;
488}
489
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700490bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
491 TEST_AND_RETURN_FALSE(hash->size() == 32);
492 hash->insert(hash->begin(),
Han Shen2643cb72012-06-26 14:45:33 -0700493 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
494 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
495 sizeof(kRSA2048SHA256Padding)));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700496 TEST_AND_RETURN_FALSE(hash->size() == 256);
497 return true;
498}
499
Jay Srinivasanf4318702012-09-24 11:56:24 -0700500bool PayloadSigner::GetMetadataSignature(const char* const metadata,
501 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700502 const string& private_key_path,
503 string* out_signature) {
504 // Calculates the hash on the updated payload. Note that the payload includes
505 // the signature op but doesn't include the signature blob at the end.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700506 vector<char> metadata_hash;
507 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
508 metadata_size,
509 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700510
511 vector<char> signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700512 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700513 private_key_path,
514 &signature));
515
516 TEST_AND_RETURN_FALSE(OmahaHashCalculator::Base64Encode(&signature[0],
517 signature.size(),
518 out_signature));
519 return true;
520}
521
522
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700523} // namespace chromeos_update_engine