blob: 900839fa962817d86f047886831ff00cc30f3a26 [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);
Gilad Arnoldfe133932014-01-14 12:25:50 -0800193 TEST_AND_RETURN_FALSE(
194 delta_performer.ParsePayloadMetadata(payload, out_manifest, &error) ==
195 DeltaPerformer::kMetadataParseSuccess);
196 *out_metadata_size = delta_performer.GetMetadataSize();
Jay Srinivasanf4318702012-09-24 11:56:24 -0700197 LOG(INFO) << "Metadata size: " << *out_metadata_size;
198 out_payload->swap(payload);
199 return true;
200}
201
Darin Petkov9574f7e2011-01-13 10:48:12 -0800202bool PayloadSigner::SignHash(const vector<char>& hash,
203 const string& private_key_path,
204 vector<char>* out_signature) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700205 LOG(INFO) << "Signing hash with private key: " << private_key_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700206 string sig_path;
207 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800208 utils::MakeTempFile("signature.XXXXXX", &sig_path, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700209 ScopedPathUnlinker sig_path_unlinker(sig_path);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700210
211 string hash_path;
212 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800213 utils::MakeTempFile("hash.XXXXXX", &hash_path, NULL));
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700214 ScopedPathUnlinker hash_path_unlinker(hash_path);
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700215 // We expect unpadded SHA256 hash coming in
216 TEST_AND_RETURN_FALSE(hash.size() == 32);
217 vector<char> padded_hash(hash);
218 PadRSA2048SHA256Hash(&padded_hash);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700219 TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700220 padded_hash.data(),
221 padded_hash.size()));
Darin Petkovd22cb292010-09-29 10:02:29 -0700222
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700223 // This runs on the server, so it's okay to cop out and call openssl
224 // executable rather than properly use the library
225 vector<string> cmd;
Mike Frysinger2149be42012-03-12 19:23:47 -0400226 base::SplitString("openssl rsautl -raw -sign -inkey x -in x -out x",
Chris Masoned903c3b2011-05-12 15:35:46 -0700227 ' ',
228 &cmd);
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700229 cmd[cmd.size() - 5] = private_key_path;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700230 cmd[cmd.size() - 3] = hash_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700231 cmd[cmd.size() - 1] = sig_path;
Darin Petkovd22cb292010-09-29 10:02:29 -0700232
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700233 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700234 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700235 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700236
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700237 vector<char> signature;
238 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800239 out_signature->swap(signature);
240 return true;
241}
Darin Petkovd22cb292010-09-29 10:02:29 -0700242
Darin Petkov9574f7e2011-01-13 10:48:12 -0800243bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700244 const vector<string>& private_key_paths,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800245 vector<char>* out_signature_blob) {
246 vector<char> hash_data;
247 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
248 unsigned_payload_path, -1, &hash_data) ==
249 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700250
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700251 vector<vector<char> > signatures;
252 for (vector<string>::const_iterator it = private_key_paths.begin(),
253 e = private_key_paths.end(); it != e; ++it) {
254 vector<char> signature;
255 TEST_AND_RETURN_FALSE(SignHash(hash_data, *it, &signature));
256 signatures.push_back(signature);
257 }
258 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800259 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700260 return true;
261}
262
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700263bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
264 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700265 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700266
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700267 string x_path;
268 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800269 utils::MakeTempFile("signed_data.XXXXXX", &x_path, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700270 ScopedPathUnlinker x_path_unlinker(x_path);
271 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
272
273 vector<char> sig_blob;
274 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700275 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700276 &sig_blob));
277 *out_length = sig_blob.size();
278 return true;
279}
280
Darin Petkovd7061ab2010-10-06 14:37:09 -0700281bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
282 const std::string& public_key_path,
283 std::vector<char>* out_hash_data) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700284 return VerifySignatureBlob(signature_blob, public_key_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700285 kSignatureMessageCurrentVersion, out_hash_data);
286}
287
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700288bool PayloadSigner::VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700289 const std::vector<char>& signature_blob,
290 const std::string& public_key_path,
291 uint32_t client_version,
292 std::vector<char>* out_hash_data) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700293 TEST_AND_RETURN_FALSE(!public_key_path.empty());
294
295 Signatures signatures;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700296 LOG(INFO) << "signature size = " << signature_blob.size();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700297 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
298 signature_blob.size()));
299
300 // Finds a signature that matches the current version.
301 int sig_index = 0;
302 for (; sig_index < signatures.signatures_size(); sig_index++) {
303 const Signatures_Signature& signature = signatures.signatures(sig_index);
304 if (signature.has_version() &&
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700305 signature.version() == client_version) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700306 break;
307 }
308 }
309 TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
310
311 const Signatures_Signature& signature = signatures.signatures(sig_index);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700312 vector<char> sig_data(signature.data().begin(), signature.data().end());
313
314 return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
315}
316
317
318bool PayloadSigner::GetRawHashFromSignature(
319 const std::vector<char>& sig_data,
320 const std::string& public_key_path,
321 std::vector<char>* out_hash_data) {
322 TEST_AND_RETURN_FALSE(!public_key_path.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700323
Darin Petkovb039d502010-12-03 09:08:04 -0800324 // The code below executes the equivalent of:
325 //
326 // openssl rsautl -verify -pubin -inkey |public_key_path|
327 // -in |sig_data| -out |out_hash_data|
Darin Petkovd7061ab2010-10-06 14:37:09 -0700328
Darin Petkovb039d502010-12-03 09:08:04 -0800329 // Loads the public key.
330 FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700331 if (!fpubkey) {
332 LOG(ERROR) << "Unable to open public key file: " << public_key_path;
333 return false;
334 }
335
Darin Petkovb039d502010-12-03 09:08:04 -0800336 char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
337 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
338 fclose(fpubkey);
339 TEST_AND_RETURN_FALSE(rsa != NULL);
340 unsigned int keysize = RSA_size(rsa);
341 if (sig_data.size() > 2 * keysize) {
342 LOG(ERROR) << "Signature size is too big for public key size.";
343 RSA_free(rsa);
344 return false;
345 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700346
Darin Petkovb039d502010-12-03 09:08:04 -0800347 // Decrypts the signature.
348 vector<char> hash_data(keysize);
349 int decrypt_size = RSA_public_decrypt(
350 sig_data.size(),
351 reinterpret_cast<const unsigned char*>(sig_data.data()),
352 reinterpret_cast<unsigned char*>(hash_data.data()),
353 rsa,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700354 RSA_NO_PADDING);
Darin Petkovb039d502010-12-03 09:08:04 -0800355 RSA_free(rsa);
356 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
357 decrypt_size <= static_cast<int>(hash_data.size()));
358 hash_data.resize(decrypt_size);
359 out_hash_data->swap(hash_data);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700360 return true;
361}
362
Darin Petkovadb3cef2011-01-13 16:16:08 -0800363bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700364 const std::string& public_key_path,
365 uint32_t client_key_check_version) {
Darin Petkovadb3cef2011-01-13 16:16:08 -0800366 vector<char> payload;
367 DeltaArchiveManifest manifest;
368 uint64_t metadata_size;
369 TEST_AND_RETURN_FALSE(LoadPayload(
370 payload_path, &payload, &manifest, &metadata_size));
371 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
372 manifest.has_signatures_size());
373 CHECK_EQ(payload.size(),
374 metadata_size + manifest.signatures_offset() +
375 manifest.signatures_size());
376 vector<char> signature_blob(
377 payload.begin() + metadata_size + manifest.signatures_offset(),
378 payload.end());
379 vector<char> signed_hash;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700380 TEST_AND_RETURN_FALSE(VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700381 signature_blob, public_key_path, client_key_check_version, &signed_hash));
Darin Petkovadb3cef2011-01-13 16:16:08 -0800382 TEST_AND_RETURN_FALSE(!signed_hash.empty());
383 vector<char> hash;
384 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
385 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700386 PadRSA2048SHA256Hash(&hash);
Darin Petkovadb3cef2011-01-13 16:16:08 -0800387 TEST_AND_RETURN_FALSE(hash == signed_hash);
388 return true;
389}
390
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700391bool PayloadSigner::PrepPayloadForHashing(
392 const string& payload_path,
393 const vector<int>& signature_sizes,
394 vector<char>* payload_out,
395 uint64_t* metadata_size_out,
396 uint64_t* signatures_offset_out) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800397 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
398
399 // Loads the payload and adds the signature op to it.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700400 vector<vector<char> > signatures;
401 for (vector<int>::const_iterator it = signature_sizes.begin(),
402 e = signature_sizes.end(); it != e; ++it) {
403 vector<char> signature(*it, 0);
404 signatures.push_back(signature);
405 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800406 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700407 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800408 &signature_blob));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800409 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
410 signature_blob.size(),
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700411 payload_out,
412 metadata_size_out,
413 signatures_offset_out));
Don Garrett2ae37872013-10-25 13:33:20 -0700414
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700415 return true;
416}
417
418bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
419 const vector<int>& signature_sizes,
420 vector<char>* out_hash_data) {
421 vector<char> payload;
422 uint64_t metadata_size;
423 uint64_t signatures_offset;
424
425 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
426 signature_sizes,
427 &payload,
428 &metadata_size,
429 &signatures_offset));
Don Garrett2ae37872013-10-25 13:33:20 -0700430
431 // Calculates the hash on the updated payload. Note that we stop calculating
432 // before we reach the signature information.
433 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
434 signatures_offset,
435 out_hash_data));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800436 return true;
437}
438
Jay Srinivasanf4318702012-09-24 11:56:24 -0700439bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700440 const vector<int>& signature_sizes,
Jay Srinivasanf4318702012-09-24 11:56:24 -0700441 vector<char>* out_metadata_hash) {
Jay Srinivasanf4318702012-09-24 11:56:24 -0700442 vector<char> payload;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700443 uint64_t metadata_size;
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700444 uint64_t signatures_offset;
445
446 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
447 signature_sizes,
448 &payload,
449 &metadata_size,
450 &signatures_offset));
Jay Srinivasanf4318702012-09-24 11:56:24 -0700451
452 // Calculates the hash on the manifest.
453 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
454 metadata_size,
455 out_metadata_hash));
456 return true;
457}
458
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700459bool PayloadSigner::AddSignatureToPayload(
460 const string& payload_path,
461 const vector<vector<char> >& signatures,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800462 const string& signed_payload_path,
463 uint64_t *out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800464 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
465
466 // Loads the payload and adds the signature op to it.
467 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700468 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800469 &signature_blob));
470 vector<char> payload;
Don Garrett2ae37872013-10-25 13:33:20 -0700471 uint64_t signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800472 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
473 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800474 &payload,
Don Garrett2ae37872013-10-25 13:33:20 -0700475 out_metadata_size,
476 &signatures_offset));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800477 // Appends the signature blob to the end of the payload and writes the new
478 // payload.
Don Garrett2ae37872013-10-25 13:33:20 -0700479 LOG(INFO) << "Payload size before signatures: " << payload.size();
480 payload.resize(signatures_offset);
481 payload.insert(payload.begin() + signatures_offset,
482 signature_blob.begin(),
483 signature_blob.end());
Darin Petkov9574f7e2011-01-13 10:48:12 -0800484 LOG(INFO) << "Signed payload size: " << payload.size();
485 TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
486 payload.data(),
487 payload.size()));
488 return true;
489}
490
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700491bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
492 TEST_AND_RETURN_FALSE(hash->size() == 32);
493 hash->insert(hash->begin(),
Han Shen2643cb72012-06-26 14:45:33 -0700494 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
495 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
496 sizeof(kRSA2048SHA256Padding)));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700497 TEST_AND_RETURN_FALSE(hash->size() == 256);
498 return true;
499}
500
Jay Srinivasanf4318702012-09-24 11:56:24 -0700501bool PayloadSigner::GetMetadataSignature(const char* const metadata,
502 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700503 const string& private_key_path,
504 string* out_signature) {
505 // Calculates the hash on the updated payload. Note that the payload includes
506 // the signature op but doesn't include the signature blob at the end.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700507 vector<char> metadata_hash;
508 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
509 metadata_size,
510 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700511
512 vector<char> signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700513 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700514 private_key_path,
515 &signature));
516
517 TEST_AND_RETURN_FALSE(OmahaHashCalculator::Base64Encode(&signature[0],
518 signature.size(),
519 out_signature));
520 return true;
521}
522
523
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700524} // namespace chromeos_update_engine