blob: 7ec483dc1373fd86effe152caf6980f61e33cf9b [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(
Gilad Arnolddaa27402014-01-23 11:56:17 -0800194 delta_performer.ParsePayloadMetadata(payload, &error) ==
Gilad Arnoldfe133932014-01-14 12:25:50 -0800195 DeltaPerformer::kMetadataParseSuccess);
Gilad Arnolddaa27402014-01-23 11:56:17 -0800196 TEST_AND_RETURN_FALSE(delta_performer.GetManifest(out_manifest));
Gilad Arnoldfe133932014-01-14 12:25:50 -0800197 *out_metadata_size = delta_performer.GetMetadataSize();
Jay Srinivasanf4318702012-09-24 11:56:24 -0700198 LOG(INFO) << "Metadata size: " << *out_metadata_size;
199 out_payload->swap(payload);
200 return true;
201}
202
Darin Petkov9574f7e2011-01-13 10:48:12 -0800203bool PayloadSigner::SignHash(const vector<char>& hash,
204 const string& private_key_path,
205 vector<char>* out_signature) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700206 LOG(INFO) << "Signing hash with private key: " << private_key_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700207 string sig_path;
208 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800209 utils::MakeTempFile("signature.XXXXXX", &sig_path, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700210 ScopedPathUnlinker sig_path_unlinker(sig_path);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700211
212 string hash_path;
213 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800214 utils::MakeTempFile("hash.XXXXXX", &hash_path, NULL));
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700215 ScopedPathUnlinker hash_path_unlinker(hash_path);
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700216 // We expect unpadded SHA256 hash coming in
217 TEST_AND_RETURN_FALSE(hash.size() == 32);
218 vector<char> padded_hash(hash);
219 PadRSA2048SHA256Hash(&padded_hash);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700220 TEST_AND_RETURN_FALSE(utils::WriteFile(hash_path.c_str(),
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700221 padded_hash.data(),
222 padded_hash.size()));
Darin Petkovd22cb292010-09-29 10:02:29 -0700223
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700224 // This runs on the server, so it's okay to cop out and call openssl
225 // executable rather than properly use the library
226 vector<string> cmd;
Mike Frysinger2149be42012-03-12 19:23:47 -0400227 base::SplitString("openssl rsautl -raw -sign -inkey x -in x -out x",
Chris Masoned903c3b2011-05-12 15:35:46 -0700228 ' ',
229 &cmd);
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700230 cmd[cmd.size() - 5] = private_key_path;
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700231 cmd[cmd.size() - 3] = hash_path;
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700232 cmd[cmd.size() - 1] = sig_path;
Darin Petkovd22cb292010-09-29 10:02:29 -0700233
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700234 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700235 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700236 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700237
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700238 vector<char> signature;
239 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800240 out_signature->swap(signature);
241 return true;
242}
Darin Petkovd22cb292010-09-29 10:02:29 -0700243
Darin Petkov9574f7e2011-01-13 10:48:12 -0800244bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700245 const vector<string>& private_key_paths,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800246 vector<char>* out_signature_blob) {
247 vector<char> hash_data;
248 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
249 unsigned_payload_path, -1, &hash_data) ==
250 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700251
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700252 vector<vector<char> > signatures;
253 for (vector<string>::const_iterator it = private_key_paths.begin(),
254 e = private_key_paths.end(); it != e; ++it) {
255 vector<char> signature;
256 TEST_AND_RETURN_FALSE(SignHash(hash_data, *it, &signature));
257 signatures.push_back(signature);
258 }
259 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800260 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700261 return true;
262}
263
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700264bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
265 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700266 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700267
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700268 string x_path;
269 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800270 utils::MakeTempFile("signed_data.XXXXXX", &x_path, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700271 ScopedPathUnlinker x_path_unlinker(x_path);
272 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
273
274 vector<char> sig_blob;
275 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700276 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700277 &sig_blob));
278 *out_length = sig_blob.size();
279 return true;
280}
281
Darin Petkovd7061ab2010-10-06 14:37:09 -0700282bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
283 const std::string& public_key_path,
284 std::vector<char>* out_hash_data) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700285 return VerifySignatureBlob(signature_blob, public_key_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700286 kSignatureMessageCurrentVersion, out_hash_data);
287}
288
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700289bool PayloadSigner::VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700290 const std::vector<char>& signature_blob,
291 const std::string& public_key_path,
292 uint32_t client_version,
293 std::vector<char>* out_hash_data) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700294 TEST_AND_RETURN_FALSE(!public_key_path.empty());
295
296 Signatures signatures;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700297 LOG(INFO) << "signature size = " << signature_blob.size();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700298 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
299 signature_blob.size()));
300
301 // Finds a signature that matches the current version.
302 int sig_index = 0;
303 for (; sig_index < signatures.signatures_size(); sig_index++) {
304 const Signatures_Signature& signature = signatures.signatures(sig_index);
305 if (signature.has_version() &&
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700306 signature.version() == client_version) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700307 break;
308 }
309 }
310 TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
311
312 const Signatures_Signature& signature = signatures.signatures(sig_index);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700313 vector<char> sig_data(signature.data().begin(), signature.data().end());
314
315 return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
316}
317
318
319bool PayloadSigner::GetRawHashFromSignature(
320 const std::vector<char>& sig_data,
321 const std::string& public_key_path,
322 std::vector<char>* out_hash_data) {
323 TEST_AND_RETURN_FALSE(!public_key_path.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700324
Darin Petkovb039d502010-12-03 09:08:04 -0800325 // The code below executes the equivalent of:
326 //
327 // openssl rsautl -verify -pubin -inkey |public_key_path|
328 // -in |sig_data| -out |out_hash_data|
Darin Petkovd7061ab2010-10-06 14:37:09 -0700329
Darin Petkovb039d502010-12-03 09:08:04 -0800330 // Loads the public key.
331 FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700332 if (!fpubkey) {
333 LOG(ERROR) << "Unable to open public key file: " << public_key_path;
334 return false;
335 }
336
Darin Petkovb039d502010-12-03 09:08:04 -0800337 char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
338 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
339 fclose(fpubkey);
340 TEST_AND_RETURN_FALSE(rsa != NULL);
341 unsigned int keysize = RSA_size(rsa);
342 if (sig_data.size() > 2 * keysize) {
343 LOG(ERROR) << "Signature size is too big for public key size.";
344 RSA_free(rsa);
345 return false;
346 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700347
Darin Petkovb039d502010-12-03 09:08:04 -0800348 // Decrypts the signature.
349 vector<char> hash_data(keysize);
350 int decrypt_size = RSA_public_decrypt(
351 sig_data.size(),
352 reinterpret_cast<const unsigned char*>(sig_data.data()),
353 reinterpret_cast<unsigned char*>(hash_data.data()),
354 rsa,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700355 RSA_NO_PADDING);
Darin Petkovb039d502010-12-03 09:08:04 -0800356 RSA_free(rsa);
357 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
358 decrypt_size <= static_cast<int>(hash_data.size()));
359 hash_data.resize(decrypt_size);
360 out_hash_data->swap(hash_data);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700361 return true;
362}
363
Darin Petkovadb3cef2011-01-13 16:16:08 -0800364bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700365 const std::string& public_key_path,
366 uint32_t client_key_check_version) {
Darin Petkovadb3cef2011-01-13 16:16:08 -0800367 vector<char> payload;
368 DeltaArchiveManifest manifest;
369 uint64_t metadata_size;
370 TEST_AND_RETURN_FALSE(LoadPayload(
371 payload_path, &payload, &manifest, &metadata_size));
372 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
373 manifest.has_signatures_size());
374 CHECK_EQ(payload.size(),
375 metadata_size + manifest.signatures_offset() +
376 manifest.signatures_size());
377 vector<char> signature_blob(
378 payload.begin() + metadata_size + manifest.signatures_offset(),
379 payload.end());
380 vector<char> signed_hash;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700381 TEST_AND_RETURN_FALSE(VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700382 signature_blob, public_key_path, client_key_check_version, &signed_hash));
Darin Petkovadb3cef2011-01-13 16:16:08 -0800383 TEST_AND_RETURN_FALSE(!signed_hash.empty());
384 vector<char> hash;
385 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
386 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700387 PadRSA2048SHA256Hash(&hash);
Darin Petkovadb3cef2011-01-13 16:16:08 -0800388 TEST_AND_RETURN_FALSE(hash == signed_hash);
389 return true;
390}
391
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700392bool PayloadSigner::PrepPayloadForHashing(
393 const string& payload_path,
394 const vector<int>& signature_sizes,
395 vector<char>* payload_out,
396 uint64_t* metadata_size_out,
397 uint64_t* signatures_offset_out) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800398 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
399
400 // Loads the payload and adds the signature op to it.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700401 vector<vector<char> > signatures;
402 for (vector<int>::const_iterator it = signature_sizes.begin(),
403 e = signature_sizes.end(); it != e; ++it) {
404 vector<char> signature(*it, 0);
405 signatures.push_back(signature);
406 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800407 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700408 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800409 &signature_blob));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800410 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
411 signature_blob.size(),
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700412 payload_out,
413 metadata_size_out,
414 signatures_offset_out));
Don Garrett2ae37872013-10-25 13:33:20 -0700415
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700416 return true;
417}
418
419bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
420 const vector<int>& signature_sizes,
421 vector<char>* out_hash_data) {
422 vector<char> payload;
423 uint64_t metadata_size;
424 uint64_t signatures_offset;
425
426 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
427 signature_sizes,
428 &payload,
429 &metadata_size,
430 &signatures_offset));
Don Garrett2ae37872013-10-25 13:33:20 -0700431
432 // Calculates the hash on the updated payload. Note that we stop calculating
433 // before we reach the signature information.
434 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
435 signatures_offset,
436 out_hash_data));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800437 return true;
438}
439
Jay Srinivasanf4318702012-09-24 11:56:24 -0700440bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700441 const vector<int>& signature_sizes,
Jay Srinivasanf4318702012-09-24 11:56:24 -0700442 vector<char>* out_metadata_hash) {
Jay Srinivasanf4318702012-09-24 11:56:24 -0700443 vector<char> payload;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700444 uint64_t metadata_size;
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700445 uint64_t signatures_offset;
446
447 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
448 signature_sizes,
449 &payload,
450 &metadata_size,
451 &signatures_offset));
Jay Srinivasanf4318702012-09-24 11:56:24 -0700452
453 // Calculates the hash on the manifest.
454 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
455 metadata_size,
456 out_metadata_hash));
457 return true;
458}
459
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700460bool PayloadSigner::AddSignatureToPayload(
461 const string& payload_path,
462 const vector<vector<char> >& signatures,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800463 const string& signed_payload_path,
464 uint64_t *out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800465 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
466
467 // Loads the payload and adds the signature op to it.
468 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700469 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800470 &signature_blob));
471 vector<char> payload;
Don Garrett2ae37872013-10-25 13:33:20 -0700472 uint64_t signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800473 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
474 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800475 &payload,
Don Garrett2ae37872013-10-25 13:33:20 -0700476 out_metadata_size,
477 &signatures_offset));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800478 // Appends the signature blob to the end of the payload and writes the new
479 // payload.
Don Garrett2ae37872013-10-25 13:33:20 -0700480 LOG(INFO) << "Payload size before signatures: " << payload.size();
481 payload.resize(signatures_offset);
482 payload.insert(payload.begin() + signatures_offset,
483 signature_blob.begin(),
484 signature_blob.end());
Darin Petkov9574f7e2011-01-13 10:48:12 -0800485 LOG(INFO) << "Signed payload size: " << payload.size();
486 TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
487 payload.data(),
488 payload.size()));
489 return true;
490}
491
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700492bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
493 TEST_AND_RETURN_FALSE(hash->size() == 32);
494 hash->insert(hash->begin(),
Han Shen2643cb72012-06-26 14:45:33 -0700495 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
496 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
497 sizeof(kRSA2048SHA256Padding)));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700498 TEST_AND_RETURN_FALSE(hash->size() == 256);
499 return true;
500}
501
Jay Srinivasanf4318702012-09-24 11:56:24 -0700502bool PayloadSigner::GetMetadataSignature(const char* const metadata,
503 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700504 const string& private_key_path,
505 string* out_signature) {
506 // Calculates the hash on the updated payload. Note that the payload includes
507 // the signature op but doesn't include the signature blob at the end.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700508 vector<char> metadata_hash;
509 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
510 metadata_size,
511 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700512
513 vector<char> signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700514 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700515 private_key_path,
516 &signature));
517
518 TEST_AND_RETURN_FALSE(OmahaHashCalculator::Base64Encode(&signature[0],
519 signature.size(),
520 out_signature));
521 return true;
522}
523
524
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700525} // namespace chromeos_update_engine