blob: 3d09737cbac1d20e68c87fad2ff382f2ce984a6f [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>
Alex Vakulenko75039d72014-03-25 12:36:28 -07008#include <base/strings/string_split.h>
9#include <base/strings/string_util.h>
Darin Petkovb039d502010-12-03 09:08:04 -080010#include <openssl/pem.h>
11
Darin Petkov9574f7e2011-01-13 10:48:12 -080012#include "update_engine/delta_performer.h"
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070013#include "update_engine/omaha_hash_calculator.h"
Alex Deymo161c4a12014-05-16 15:56:21 -070014#include "update_engine/payload_generator/delta_diff_generator.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()) {
Don Garrett2ae37872013-10-25 13:33:20 -0700136 // The signature op is tied to the size of the signature blob, but not it's
137 // contents. We don't allow the manifest to change if there is already an op
138 // present, because that might invalidate previously generated
139 // hashes/signatures.
140 if (manifest.signatures_size() != signature_blob_size) {
141 LOG(ERROR) << "Attempt to insert different signature sized blob. "
142 << "(current:" << manifest.signatures_size()
143 << "new:" << signature_blob_size << ")";
144 return false;
145 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800146
Don Garrett2ae37872013-10-25 13:33:20 -0700147 LOG(INFO) << "Matching signature sizes already present.";
148 } else {
149 // Updates the manifest to include the signature operation.
150 DeltaDiffGenerator::AddSignatureOp(payload.size() - metadata_size,
151 signature_blob_size,
152 &manifest);
153
154 // Updates the payload to include the new manifest.
155 string serialized_manifest;
156 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
157 LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
158 payload.erase(payload.begin() + kProtobufOffset,
159 payload.begin() + metadata_size);
160 payload.insert(payload.begin() + kProtobufOffset,
161 serialized_manifest.begin(),
162 serialized_manifest.end());
163
164 // Updates the protobuf size.
165 uint64_t size_be = htobe64(serialized_manifest.size());
166 memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
167 metadata_size = serialized_manifest.size() + kProtobufOffset;
168
169 LOG(INFO) << "Updated payload size: " << payload.size();
170 LOG(INFO) << "Updated metadata size: " << metadata_size;
171 }
172
Darin Petkov9574f7e2011-01-13 10:48:12 -0800173 out_payload->swap(payload);
Don Garrett2ae37872013-10-25 13:33:20 -0700174 *out_metadata_size = metadata_size;
175 *out_signatures_offset = metadata_size + manifest.signatures_offset();
176 LOG(INFO) << "Signature Blob Offset: " << *out_signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800177 return true;
178}
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700179} // namespace
Darin Petkov9574f7e2011-01-13 10:48:12 -0800180
Jay Srinivasanf4318702012-09-24 11:56:24 -0700181bool PayloadSigner::LoadPayload(const string& payload_path,
182 vector<char>* out_payload,
183 DeltaArchiveManifest* out_manifest,
184 uint64_t* out_metadata_size) {
185 vector<char> payload;
186 // Loads the payload and parses the manifest.
187 TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
188 LOG(INFO) << "Payload size: " << payload.size();
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700189 ErrorCode error = ErrorCode::kSuccess;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700190 InstallPlan install_plan;
Jay Srinivasanf0572052012-10-23 18:12:56 -0700191 DeltaPerformer delta_performer(NULL, NULL, &install_plan);
Gilad Arnoldfe133932014-01-14 12:25:50 -0800192 TEST_AND_RETURN_FALSE(
Gilad Arnolddaa27402014-01-23 11:56:17 -0800193 delta_performer.ParsePayloadMetadata(payload, &error) ==
Gilad Arnoldfe133932014-01-14 12:25:50 -0800194 DeltaPerformer::kMetadataParseSuccess);
Gilad Arnolddaa27402014-01-23 11:56:17 -0800195 TEST_AND_RETURN_FALSE(delta_performer.GetManifest(out_manifest));
Gilad Arnoldfe133932014-01-14 12:25:50 -0800196 *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
Alex Deymo719bfff2014-07-11 12:12:32 -0700233 // When running unittests, we need to use the openssl version from the
234 // SYSROOT instead of the one on the $PATH (host).
235 cmd[0] = utils::GetPathOnBoard("openssl");
236
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700237 int return_code = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700238 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700239 TEST_AND_RETURN_FALSE(return_code == 0);
Darin Petkovd22cb292010-09-29 10:02:29 -0700240
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700241 vector<char> signature;
242 TEST_AND_RETURN_FALSE(utils::ReadFile(sig_path, &signature));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800243 out_signature->swap(signature);
244 return true;
245}
Darin Petkovd22cb292010-09-29 10:02:29 -0700246
Darin Petkov9574f7e2011-01-13 10:48:12 -0800247bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700248 const vector<string>& private_key_paths,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800249 vector<char>* out_signature_blob) {
250 vector<char> hash_data;
251 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfFile(
252 unsigned_payload_path, -1, &hash_data) ==
253 utils::FileSize(unsigned_payload_path));
Darin Petkovd22cb292010-09-29 10:02:29 -0700254
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700255 vector<vector<char> > signatures;
256 for (vector<string>::const_iterator it = private_key_paths.begin(),
257 e = private_key_paths.end(); it != e; ++it) {
258 vector<char> signature;
259 TEST_AND_RETURN_FALSE(SignHash(hash_data, *it, &signature));
260 signatures.push_back(signature);
261 }
262 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800263 out_signature_blob));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700264 return true;
265}
266
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700267bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
268 uint64_t* out_length) {
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700269 DCHECK(out_length);
Darin Petkovd22cb292010-09-29 10:02:29 -0700270
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700271 string x_path;
272 TEST_AND_RETURN_FALSE(
Gilad Arnolda6742b32014-01-11 00:18:34 -0800273 utils::MakeTempFile("signed_data.XXXXXX", &x_path, NULL));
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700274 ScopedPathUnlinker x_path_unlinker(x_path);
275 TEST_AND_RETURN_FALSE(utils::WriteFile(x_path.c_str(), "x", 1));
276
277 vector<char> sig_blob;
278 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(x_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700279 private_key_paths,
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700280 &sig_blob));
281 *out_length = sig_blob.size();
282 return true;
283}
284
Darin Petkovd7061ab2010-10-06 14:37:09 -0700285bool PayloadSigner::VerifySignature(const std::vector<char>& signature_blob,
286 const std::string& public_key_path,
287 std::vector<char>* out_hash_data) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700288 return VerifySignatureBlob(signature_blob, public_key_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700289 kSignatureMessageCurrentVersion, out_hash_data);
290}
291
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700292bool PayloadSigner::VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700293 const std::vector<char>& signature_blob,
294 const std::string& public_key_path,
295 uint32_t client_version,
296 std::vector<char>* out_hash_data) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700297 TEST_AND_RETURN_FALSE(!public_key_path.empty());
298
299 Signatures signatures;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700300 LOG(INFO) << "signature size = " << signature_blob.size();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700301 TEST_AND_RETURN_FALSE(signatures.ParseFromArray(&signature_blob[0],
302 signature_blob.size()));
303
304 // Finds a signature that matches the current version.
305 int sig_index = 0;
306 for (; sig_index < signatures.signatures_size(); sig_index++) {
307 const Signatures_Signature& signature = signatures.signatures(sig_index);
308 if (signature.has_version() &&
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700309 signature.version() == client_version) {
Darin Petkovd7061ab2010-10-06 14:37:09 -0700310 break;
311 }
312 }
313 TEST_AND_RETURN_FALSE(sig_index < signatures.signatures_size());
314
315 const Signatures_Signature& signature = signatures.signatures(sig_index);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700316 vector<char> sig_data(signature.data().begin(), signature.data().end());
317
318 return GetRawHashFromSignature(sig_data, public_key_path, out_hash_data);
319}
320
321
322bool PayloadSigner::GetRawHashFromSignature(
323 const std::vector<char>& sig_data,
324 const std::string& public_key_path,
325 std::vector<char>* out_hash_data) {
326 TEST_AND_RETURN_FALSE(!public_key_path.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700327
Darin Petkovb039d502010-12-03 09:08:04 -0800328 // The code below executes the equivalent of:
329 //
330 // openssl rsautl -verify -pubin -inkey |public_key_path|
331 // -in |sig_data| -out |out_hash_data|
Darin Petkovd7061ab2010-10-06 14:37:09 -0700332
Darin Petkovb039d502010-12-03 09:08:04 -0800333 // Loads the public key.
334 FILE* fpubkey = fopen(public_key_path.c_str(), "rb");
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700335 if (!fpubkey) {
336 LOG(ERROR) << "Unable to open public key file: " << public_key_path;
337 return false;
338 }
339
Darin Petkovb039d502010-12-03 09:08:04 -0800340 char dummy_password[] = { ' ', 0 }; // Ensure no password is read from stdin.
341 RSA* rsa = PEM_read_RSA_PUBKEY(fpubkey, NULL, NULL, dummy_password);
342 fclose(fpubkey);
343 TEST_AND_RETURN_FALSE(rsa != NULL);
344 unsigned int keysize = RSA_size(rsa);
345 if (sig_data.size() > 2 * keysize) {
346 LOG(ERROR) << "Signature size is too big for public key size.";
347 RSA_free(rsa);
348 return false;
349 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700350
Darin Petkovb039d502010-12-03 09:08:04 -0800351 // Decrypts the signature.
352 vector<char> hash_data(keysize);
353 int decrypt_size = RSA_public_decrypt(
354 sig_data.size(),
355 reinterpret_cast<const unsigned char*>(sig_data.data()),
356 reinterpret_cast<unsigned char*>(hash_data.data()),
357 rsa,
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700358 RSA_NO_PADDING);
Darin Petkovb039d502010-12-03 09:08:04 -0800359 RSA_free(rsa);
360 TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
361 decrypt_size <= static_cast<int>(hash_data.size()));
362 hash_data.resize(decrypt_size);
363 out_hash_data->swap(hash_data);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700364 return true;
365}
366
Darin Petkovadb3cef2011-01-13 16:16:08 -0800367bool PayloadSigner::VerifySignedPayload(const std::string& payload_path,
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700368 const std::string& public_key_path,
369 uint32_t client_key_check_version) {
Darin Petkovadb3cef2011-01-13 16:16:08 -0800370 vector<char> payload;
371 DeltaArchiveManifest manifest;
372 uint64_t metadata_size;
373 TEST_AND_RETURN_FALSE(LoadPayload(
374 payload_path, &payload, &manifest, &metadata_size));
375 TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
376 manifest.has_signatures_size());
377 CHECK_EQ(payload.size(),
378 metadata_size + manifest.signatures_offset() +
379 manifest.signatures_size());
380 vector<char> signature_blob(
381 payload.begin() + metadata_size + manifest.signatures_offset(),
382 payload.end());
383 vector<char> signed_hash;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700384 TEST_AND_RETURN_FALSE(VerifySignatureBlob(
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700385 signature_blob, public_key_path, client_key_check_version, &signed_hash));
Darin Petkovadb3cef2011-01-13 16:16:08 -0800386 TEST_AND_RETURN_FALSE(!signed_hash.empty());
387 vector<char> hash;
388 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(
389 payload.data(), metadata_size + manifest.signatures_offset(), &hash));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700390 PadRSA2048SHA256Hash(&hash);
Darin Petkovadb3cef2011-01-13 16:16:08 -0800391 TEST_AND_RETURN_FALSE(hash == signed_hash);
392 return true;
393}
394
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700395bool PayloadSigner::PrepPayloadForHashing(
396 const string& payload_path,
397 const vector<int>& signature_sizes,
398 vector<char>* payload_out,
399 uint64_t* metadata_size_out,
400 uint64_t* signatures_offset_out) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800401 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
402
403 // Loads the payload and adds the signature op to it.
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700404 vector<vector<char> > signatures;
405 for (vector<int>::const_iterator it = signature_sizes.begin(),
406 e = signature_sizes.end(); it != e; ++it) {
407 vector<char> signature(*it, 0);
408 signatures.push_back(signature);
409 }
Darin Petkov9574f7e2011-01-13 10:48:12 -0800410 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700411 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800412 &signature_blob));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800413 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
414 signature_blob.size(),
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700415 payload_out,
416 metadata_size_out,
417 signatures_offset_out));
Don Garrett2ae37872013-10-25 13:33:20 -0700418
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700419 return true;
420}
421
422bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
423 const vector<int>& signature_sizes,
424 vector<char>* out_hash_data) {
425 vector<char> payload;
426 uint64_t metadata_size;
427 uint64_t signatures_offset;
428
429 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
430 signature_sizes,
431 &payload,
432 &metadata_size,
433 &signatures_offset));
Don Garrett2ae37872013-10-25 13:33:20 -0700434
435 // Calculates the hash on the updated payload. Note that we stop calculating
436 // before we reach the signature information.
437 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
438 signatures_offset,
439 out_hash_data));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800440 return true;
441}
442
Jay Srinivasanf4318702012-09-24 11:56:24 -0700443bool PayloadSigner::HashMetadataForSigning(const string& payload_path,
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700444 const vector<int>& signature_sizes,
Jay Srinivasanf4318702012-09-24 11:56:24 -0700445 vector<char>* out_metadata_hash) {
Jay Srinivasanf4318702012-09-24 11:56:24 -0700446 vector<char> payload;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700447 uint64_t metadata_size;
Don Garrettc2e9f5f2013-10-18 16:42:40 -0700448 uint64_t signatures_offset;
449
450 TEST_AND_RETURN_FALSE(PrepPayloadForHashing(payload_path,
451 signature_sizes,
452 &payload,
453 &metadata_size,
454 &signatures_offset));
Jay Srinivasanf4318702012-09-24 11:56:24 -0700455
456 // Calculates the hash on the manifest.
457 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(&payload[0],
458 metadata_size,
459 out_metadata_hash));
460 return true;
461}
462
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700463bool PayloadSigner::AddSignatureToPayload(
464 const string& payload_path,
465 const vector<vector<char> >& signatures,
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800466 const string& signed_payload_path,
467 uint64_t *out_metadata_size) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800468 // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
469
470 // Loads the payload and adds the signature op to it.
471 vector<char> signature_blob;
Andrew de los Reyesc24e3f32011-08-30 15:45:20 -0700472 TEST_AND_RETURN_FALSE(ConvertSignatureToProtobufBlob(signatures,
Darin Petkov9574f7e2011-01-13 10:48:12 -0800473 &signature_blob));
474 vector<char> payload;
Don Garrett2ae37872013-10-25 13:33:20 -0700475 uint64_t signatures_offset;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800476 TEST_AND_RETURN_FALSE(AddSignatureOpToPayload(payload_path,
477 signature_blob.size(),
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800478 &payload,
Don Garrett2ae37872013-10-25 13:33:20 -0700479 out_metadata_size,
480 &signatures_offset));
Darin Petkov9574f7e2011-01-13 10:48:12 -0800481 // Appends the signature blob to the end of the payload and writes the new
482 // payload.
Don Garrett2ae37872013-10-25 13:33:20 -0700483 LOG(INFO) << "Payload size before signatures: " << payload.size();
484 payload.resize(signatures_offset);
485 payload.insert(payload.begin() + signatures_offset,
486 signature_blob.begin(),
487 signature_blob.end());
Darin Petkov9574f7e2011-01-13 10:48:12 -0800488 LOG(INFO) << "Signed payload size: " << payload.size();
489 TEST_AND_RETURN_FALSE(utils::WriteFile(signed_payload_path.c_str(),
490 payload.data(),
491 payload.size()));
492 return true;
493}
494
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700495bool PayloadSigner::PadRSA2048SHA256Hash(std::vector<char>* hash) {
496 TEST_AND_RETURN_FALSE(hash->size() == 32);
497 hash->insert(hash->begin(),
Han Shen2643cb72012-06-26 14:45:33 -0700498 reinterpret_cast<const char*>(kRSA2048SHA256Padding),
499 reinterpret_cast<const char*>(kRSA2048SHA256Padding +
500 sizeof(kRSA2048SHA256Padding)));
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -0700501 TEST_AND_RETURN_FALSE(hash->size() == 256);
502 return true;
503}
504
Jay Srinivasanf4318702012-09-24 11:56:24 -0700505bool PayloadSigner::GetMetadataSignature(const char* const metadata,
506 size_t metadata_size,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700507 const string& private_key_path,
508 string* out_signature) {
509 // Calculates the hash on the updated payload. Note that the payload includes
510 // the signature op but doesn't include the signature blob at the end.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700511 vector<char> metadata_hash;
512 TEST_AND_RETURN_FALSE(OmahaHashCalculator::RawHashOfBytes(metadata,
513 metadata_size,
514 &metadata_hash));
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700515
516 vector<char> signature;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700517 TEST_AND_RETURN_FALSE(SignHash(metadata_hash,
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700518 private_key_path,
519 &signature));
520
521 TEST_AND_RETURN_FALSE(OmahaHashCalculator::Base64Encode(&signature[0],
522 signature.size(),
523 out_signature));
524 return true;
525}
526
527
Andrew de los Reyes0c440052010-08-20 11:25:54 -0700528} // namespace chromeos_update_engine