payload_signer.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. //
  2. // Copyright (C) 2011 The Android Open Source Project
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #include "update_engine/payload_generator/payload_signer.h"
  17. #include <endian.h>
  18. #include <utility>
  19. #include <base/logging.h>
  20. #include <base/strings/string_number_conversions.h>
  21. #include <base/strings/string_split.h>
  22. #include <base/strings/string_util.h>
  23. #include <brillo/data_encoding.h>
  24. #include <openssl/err.h>
  25. #include <openssl/pem.h>
  26. #include "update_engine/common/constants.h"
  27. #include "update_engine/common/hash_calculator.h"
  28. #include "update_engine/common/subprocess.h"
  29. #include "update_engine/common/utils.h"
  30. #include "update_engine/payload_consumer/delta_performer.h"
  31. #include "update_engine/payload_consumer/payload_constants.h"
  32. #include "update_engine/payload_consumer/payload_metadata.h"
  33. #include "update_engine/payload_consumer/payload_verifier.h"
  34. #include "update_engine/payload_generator/delta_diff_generator.h"
  35. #include "update_engine/payload_generator/payload_file.h"
  36. #include "update_engine/update_metadata.pb.h"
  37. using std::string;
  38. using std::vector;
  39. namespace chromeos_update_engine {
  40. namespace {
  41. // The payload verifier will check all the signatures included in the payload
  42. // regardless of the version field. Old version of the verifier require the
  43. // version field to be included and be 1.
  44. const uint32_t kSignatureMessageLegacyVersion = 1;
  45. // Given raw |signatures|, packs them into a protobuf and serializes it into a
  46. // string. Returns true on success, false otherwise.
  47. bool ConvertSignaturesToProtobuf(const vector<brillo::Blob>& signatures,
  48. string* out_serialized_signature) {
  49. // Pack it into a protobuf
  50. Signatures out_message;
  51. for (const brillo::Blob& signature : signatures) {
  52. Signatures::Signature* sig_message = out_message.add_signatures();
  53. // Set all the signatures with the same version number.
  54. sig_message->set_version(kSignatureMessageLegacyVersion);
  55. sig_message->set_data(signature.data(), signature.size());
  56. }
  57. // Serialize protobuf
  58. TEST_AND_RETURN_FALSE(
  59. out_message.SerializeToString(out_serialized_signature));
  60. LOG(INFO) << "Signature blob size: " << out_serialized_signature->size();
  61. return true;
  62. }
  63. // Given an unsigned payload under |payload_path| and the |payload_signature|
  64. // and |metadata_signature| generates an updated payload that includes the
  65. // signatures. It populates |out_metadata_size| with the size of the final
  66. // manifest after adding the dummy signature operation, and
  67. // |out_signatures_offset| with the expected offset for the new blob, and
  68. // |out_metadata_signature_size| which will be size of |metadata_signature|
  69. // if the payload major version supports metadata signature, 0 otherwise.
  70. // Returns true on success, false otherwise.
  71. bool AddSignatureBlobToPayload(const string& payload_path,
  72. const string& payload_signature,
  73. const string& metadata_signature,
  74. brillo::Blob* out_payload,
  75. uint64_t* out_metadata_size,
  76. uint32_t* out_metadata_signature_size,
  77. uint64_t* out_signatures_offset) {
  78. uint64_t manifest_offset = 20;
  79. const int kProtobufSizeOffset = 12;
  80. brillo::Blob payload;
  81. TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
  82. PayloadMetadata payload_metadata;
  83. TEST_AND_RETURN_FALSE(payload_metadata.ParsePayloadHeader(payload));
  84. uint64_t metadata_size = payload_metadata.GetMetadataSize();
  85. uint32_t metadata_signature_size =
  86. payload_metadata.GetMetadataSignatureSize();
  87. if (payload_metadata.GetMajorVersion() == kBrilloMajorPayloadVersion) {
  88. // Write metadata signature size in header.
  89. uint32_t metadata_signature_size_be = htobe32(metadata_signature.size());
  90. memcpy(payload.data() + manifest_offset,
  91. &metadata_signature_size_be,
  92. sizeof(metadata_signature_size_be));
  93. manifest_offset += sizeof(metadata_signature_size_be);
  94. // Replace metadata signature.
  95. payload.erase(payload.begin() + metadata_size,
  96. payload.begin() + metadata_size + metadata_signature_size);
  97. payload.insert(payload.begin() + metadata_size,
  98. metadata_signature.begin(),
  99. metadata_signature.end());
  100. metadata_signature_size = metadata_signature.size();
  101. LOG(INFO) << "Metadata signature size: " << metadata_signature_size;
  102. }
  103. DeltaArchiveManifest manifest;
  104. TEST_AND_RETURN_FALSE(payload_metadata.GetManifest(payload, &manifest));
  105. // Is there already a signature op in place?
  106. if (manifest.has_signatures_size()) {
  107. // The signature op is tied to the size of the signature blob, but not it's
  108. // contents. We don't allow the manifest to change if there is already an op
  109. // present, because that might invalidate previously generated
  110. // hashes/signatures.
  111. if (manifest.signatures_size() != payload_signature.size()) {
  112. LOG(ERROR) << "Attempt to insert different signature sized blob. "
  113. << "(current:" << manifest.signatures_size()
  114. << "new:" << payload_signature.size() << ")";
  115. return false;
  116. }
  117. LOG(INFO) << "Matching signature sizes already present.";
  118. } else {
  119. // Updates the manifest to include the signature operation.
  120. PayloadSigner::AddSignatureToManifest(
  121. payload.size() - metadata_size - metadata_signature_size,
  122. payload_signature.size(),
  123. payload_metadata.GetMajorVersion() == kChromeOSMajorPayloadVersion,
  124. &manifest);
  125. // Updates the payload to include the new manifest.
  126. string serialized_manifest;
  127. TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
  128. LOG(INFO) << "Updated protobuf size: " << serialized_manifest.size();
  129. payload.erase(payload.begin() + manifest_offset,
  130. payload.begin() + metadata_size);
  131. payload.insert(payload.begin() + manifest_offset,
  132. serialized_manifest.begin(),
  133. serialized_manifest.end());
  134. // Updates the protobuf size.
  135. uint64_t size_be = htobe64(serialized_manifest.size());
  136. memcpy(&payload[kProtobufSizeOffset], &size_be, sizeof(size_be));
  137. metadata_size = serialized_manifest.size() + manifest_offset;
  138. LOG(INFO) << "Updated payload size: " << payload.size();
  139. LOG(INFO) << "Updated metadata size: " << metadata_size;
  140. }
  141. uint64_t signatures_offset =
  142. metadata_size + metadata_signature_size + manifest.signatures_offset();
  143. LOG(INFO) << "Signature Blob Offset: " << signatures_offset;
  144. payload.resize(signatures_offset);
  145. payload.insert(payload.begin() + signatures_offset,
  146. payload_signature.begin(),
  147. payload_signature.end());
  148. *out_payload = std::move(payload);
  149. *out_metadata_size = metadata_size;
  150. *out_metadata_signature_size = metadata_signature_size;
  151. *out_signatures_offset = signatures_offset;
  152. return true;
  153. }
  154. // Given a |payload| with correct signature op and metadata signature size in
  155. // header and |metadata_size|, |metadata_signature_size|, |signatures_offset|,
  156. // calculate hash for payload and metadata, save it to |out_hash_data| and
  157. // |out_metadata_hash|.
  158. bool CalculateHashFromPayload(const brillo::Blob& payload,
  159. const uint64_t metadata_size,
  160. const uint32_t metadata_signature_size,
  161. const uint64_t signatures_offset,
  162. brillo::Blob* out_hash_data,
  163. brillo::Blob* out_metadata_hash) {
  164. if (out_metadata_hash) {
  165. // Calculates the hash on the manifest.
  166. TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfBytes(
  167. payload.data(), metadata_size, out_metadata_hash));
  168. }
  169. if (out_hash_data) {
  170. // Calculates the hash on the updated payload. Note that we skip metadata
  171. // signature and payload signature.
  172. HashCalculator calc;
  173. TEST_AND_RETURN_FALSE(calc.Update(payload.data(), metadata_size));
  174. TEST_AND_RETURN_FALSE(signatures_offset >=
  175. metadata_size + metadata_signature_size);
  176. TEST_AND_RETURN_FALSE(calc.Update(
  177. payload.data() + metadata_size + metadata_signature_size,
  178. signatures_offset - metadata_size - metadata_signature_size));
  179. TEST_AND_RETURN_FALSE(calc.Finalize());
  180. *out_hash_data = calc.raw_hash();
  181. }
  182. return true;
  183. }
  184. } // namespace
  185. void PayloadSigner::AddSignatureToManifest(uint64_t signature_blob_offset,
  186. uint64_t signature_blob_length,
  187. bool add_dummy_op,
  188. DeltaArchiveManifest* manifest) {
  189. LOG(INFO) << "Making room for signature in file";
  190. manifest->set_signatures_offset(signature_blob_offset);
  191. LOG(INFO) << "set? " << manifest->has_signatures_offset();
  192. manifest->set_signatures_offset(signature_blob_offset);
  193. manifest->set_signatures_size(signature_blob_length);
  194. // Add a dummy op at the end to appease older clients
  195. if (add_dummy_op) {
  196. InstallOperation* dummy_op = manifest->add_kernel_install_operations();
  197. dummy_op->set_type(InstallOperation::REPLACE);
  198. dummy_op->set_data_offset(signature_blob_offset);
  199. dummy_op->set_data_length(signature_blob_length);
  200. Extent* dummy_extent = dummy_op->add_dst_extents();
  201. // Tell the dummy op to write this data to a big sparse hole
  202. dummy_extent->set_start_block(kSparseHole);
  203. dummy_extent->set_num_blocks(
  204. utils::DivRoundUp(signature_blob_length, kBlockSize));
  205. }
  206. }
  207. bool PayloadSigner::VerifySignedPayload(const string& payload_path,
  208. const string& public_key_path) {
  209. brillo::Blob payload;
  210. TEST_AND_RETURN_FALSE(utils::ReadFile(payload_path, &payload));
  211. PayloadMetadata payload_metadata;
  212. TEST_AND_RETURN_FALSE(payload_metadata.ParsePayloadHeader(payload));
  213. DeltaArchiveManifest manifest;
  214. TEST_AND_RETURN_FALSE(payload_metadata.GetManifest(payload, &manifest));
  215. TEST_AND_RETURN_FALSE(manifest.has_signatures_offset() &&
  216. manifest.has_signatures_size());
  217. uint64_t metadata_size = payload_metadata.GetMetadataSize();
  218. uint32_t metadata_signature_size =
  219. payload_metadata.GetMetadataSignatureSize();
  220. uint64_t signatures_offset =
  221. metadata_size + metadata_signature_size + manifest.signatures_offset();
  222. CHECK_EQ(payload.size(), signatures_offset + manifest.signatures_size());
  223. brillo::Blob payload_hash, metadata_hash;
  224. TEST_AND_RETURN_FALSE(CalculateHashFromPayload(payload,
  225. metadata_size,
  226. metadata_signature_size,
  227. signatures_offset,
  228. &payload_hash,
  229. &metadata_hash));
  230. string signature(payload.begin() + signatures_offset, payload.end());
  231. string public_key;
  232. TEST_AND_RETURN_FALSE(utils::ReadFile(public_key_path, &public_key));
  233. TEST_AND_RETURN_FALSE(payload_hash.size() == kSHA256Size);
  234. TEST_AND_RETURN_FALSE(
  235. PayloadVerifier::VerifySignature(signature, public_key, payload_hash));
  236. if (metadata_signature_size) {
  237. signature.assign(payload.begin() + metadata_size,
  238. payload.begin() + metadata_size + metadata_signature_size);
  239. TEST_AND_RETURN_FALSE(metadata_hash.size() == kSHA256Size);
  240. TEST_AND_RETURN_FALSE(
  241. PayloadVerifier::VerifySignature(signature, public_key, metadata_hash));
  242. }
  243. return true;
  244. }
  245. bool PayloadSigner::SignHash(const brillo::Blob& hash,
  246. const string& private_key_path,
  247. brillo::Blob* out_signature) {
  248. LOG(INFO) << "Signing hash with private key: " << private_key_path;
  249. // We expect unpadded SHA256 hash coming in
  250. TEST_AND_RETURN_FALSE(hash.size() == kSHA256Size);
  251. // The code below executes the equivalent of:
  252. //
  253. // openssl rsautl -raw -sign -inkey |private_key_path|
  254. // -in |padded_hash| -out |out_signature|
  255. FILE* fprikey = fopen(private_key_path.c_str(), "rb");
  256. TEST_AND_RETURN_FALSE(fprikey != nullptr);
  257. RSA* rsa = PEM_read_RSAPrivateKey(fprikey, nullptr, nullptr, nullptr);
  258. fclose(fprikey);
  259. TEST_AND_RETURN_FALSE(rsa != nullptr);
  260. brillo::Blob padded_hash = hash;
  261. PayloadVerifier::PadRSASHA256Hash(&padded_hash, RSA_size(rsa));
  262. brillo::Blob signature(RSA_size(rsa));
  263. ssize_t signature_size = RSA_private_encrypt(padded_hash.size(),
  264. padded_hash.data(),
  265. signature.data(),
  266. rsa,
  267. RSA_NO_PADDING);
  268. RSA_free(rsa);
  269. if (signature_size < 0) {
  270. LOG(ERROR) << "Signing hash failed: "
  271. << ERR_error_string(ERR_get_error(), nullptr);
  272. return false;
  273. }
  274. TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
  275. signature.size());
  276. out_signature->swap(signature);
  277. return true;
  278. }
  279. bool PayloadSigner::SignHashWithKeys(const brillo::Blob& hash_data,
  280. const vector<string>& private_key_paths,
  281. string* out_serialized_signature) {
  282. vector<brillo::Blob> signatures;
  283. for (const string& path : private_key_paths) {
  284. brillo::Blob signature;
  285. TEST_AND_RETURN_FALSE(SignHash(hash_data, path, &signature));
  286. signatures.push_back(signature);
  287. }
  288. TEST_AND_RETURN_FALSE(
  289. ConvertSignaturesToProtobuf(signatures, out_serialized_signature));
  290. return true;
  291. }
  292. bool PayloadSigner::SignPayload(const string& unsigned_payload_path,
  293. const vector<string>& private_key_paths,
  294. const uint64_t metadata_size,
  295. const uint32_t metadata_signature_size,
  296. const uint64_t signatures_offset,
  297. string* out_serialized_signature) {
  298. brillo::Blob payload;
  299. TEST_AND_RETURN_FALSE(utils::ReadFile(unsigned_payload_path, &payload));
  300. brillo::Blob hash_data;
  301. TEST_AND_RETURN_FALSE(CalculateHashFromPayload(payload,
  302. metadata_size,
  303. metadata_signature_size,
  304. signatures_offset,
  305. &hash_data,
  306. nullptr));
  307. TEST_AND_RETURN_FALSE(
  308. SignHashWithKeys(hash_data, private_key_paths, out_serialized_signature));
  309. return true;
  310. }
  311. bool PayloadSigner::SignatureBlobLength(const vector<string>& private_key_paths,
  312. uint64_t* out_length) {
  313. DCHECK(out_length);
  314. brillo::Blob hash_blob;
  315. TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfData({'x'}, &hash_blob));
  316. string sig_blob;
  317. TEST_AND_RETURN_FALSE(
  318. SignHashWithKeys(hash_blob, private_key_paths, &sig_blob));
  319. *out_length = sig_blob.size();
  320. return true;
  321. }
  322. bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
  323. const vector<int>& signature_sizes,
  324. brillo::Blob* out_payload_hash_data,
  325. brillo::Blob* out_metadata_hash) {
  326. // Create a signature blob with signatures filled with 0.
  327. // Will be used for both payload signature and metadata signature.
  328. vector<brillo::Blob> signatures;
  329. for (int signature_size : signature_sizes) {
  330. signatures.emplace_back(signature_size, 0);
  331. }
  332. string signature;
  333. TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(signatures, &signature));
  334. brillo::Blob payload;
  335. uint64_t metadata_size, signatures_offset;
  336. uint32_t metadata_signature_size;
  337. // Prepare payload for hashing.
  338. TEST_AND_RETURN_FALSE(AddSignatureBlobToPayload(payload_path,
  339. signature,
  340. signature,
  341. &payload,
  342. &metadata_size,
  343. &metadata_signature_size,
  344. &signatures_offset));
  345. TEST_AND_RETURN_FALSE(CalculateHashFromPayload(payload,
  346. metadata_size,
  347. metadata_signature_size,
  348. signatures_offset,
  349. out_payload_hash_data,
  350. out_metadata_hash));
  351. return true;
  352. }
  353. bool PayloadSigner::AddSignatureToPayload(
  354. const string& payload_path,
  355. const vector<brillo::Blob>& payload_signatures,
  356. const vector<brillo::Blob>& metadata_signatures,
  357. const string& signed_payload_path,
  358. uint64_t* out_metadata_size) {
  359. // TODO(petkov): Reduce memory usage -- the payload is manipulated in memory.
  360. // Loads the payload and adds the signature op to it.
  361. string payload_signature, metadata_signature;
  362. TEST_AND_RETURN_FALSE(
  363. ConvertSignaturesToProtobuf(payload_signatures, &payload_signature));
  364. if (!metadata_signatures.empty()) {
  365. TEST_AND_RETURN_FALSE(
  366. ConvertSignaturesToProtobuf(metadata_signatures, &metadata_signature));
  367. }
  368. brillo::Blob payload;
  369. uint64_t signatures_offset;
  370. uint32_t metadata_signature_size;
  371. TEST_AND_RETURN_FALSE(AddSignatureBlobToPayload(payload_path,
  372. payload_signature,
  373. metadata_signature,
  374. &payload,
  375. out_metadata_size,
  376. &metadata_signature_size,
  377. &signatures_offset));
  378. LOG(INFO) << "Signed payload size: " << payload.size();
  379. TEST_AND_RETURN_FALSE(utils::WriteFile(
  380. signed_payload_path.c_str(), payload.data(), payload.size()));
  381. return true;
  382. }
  383. bool PayloadSigner::GetMetadataSignature(const void* const metadata,
  384. size_t metadata_size,
  385. const string& private_key_path,
  386. string* out_signature) {
  387. // Calculates the hash on the updated payload. Note that the payload includes
  388. // the signature op but doesn't include the signature blob at the end.
  389. brillo::Blob metadata_hash;
  390. TEST_AND_RETURN_FALSE(
  391. HashCalculator::RawHashOfBytes(metadata, metadata_size, &metadata_hash));
  392. brillo::Blob signature;
  393. TEST_AND_RETURN_FALSE(SignHash(metadata_hash, private_key_path, &signature));
  394. *out_signature = brillo::data_encoding::Base64Encode(signature);
  395. return true;
  396. }
  397. bool PayloadSigner::ExtractPayloadProperties(
  398. const string& payload_path, brillo::KeyValueStore* properties) {
  399. brillo::Blob payload;
  400. TEST_AND_RETURN_FALSE(
  401. utils::ReadFileChunk(payload_path, 0, kMaxPayloadHeaderSize, &payload));
  402. PayloadMetadata payload_metadata;
  403. TEST_AND_RETURN_FALSE(payload_metadata.ParsePayloadHeader(payload));
  404. uint64_t metadata_size = payload_metadata.GetMetadataSize();
  405. uint64_t file_size = utils::FileSize(payload_path);
  406. properties->SetString(kPayloadPropertyFileSize, std::to_string(file_size));
  407. properties->SetString(kPayloadPropertyMetadataSize,
  408. std::to_string(metadata_size));
  409. brillo::Blob file_hash, metadata_hash;
  410. TEST_AND_RETURN_FALSE(
  411. HashCalculator::RawHashOfFile(payload_path, file_size, &file_hash) ==
  412. static_cast<off_t>(file_size));
  413. TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfFile(
  414. payload_path, metadata_size, &metadata_hash) ==
  415. static_cast<off_t>(metadata_size));
  416. properties->SetString(kPayloadPropertyFileHash,
  417. brillo::data_encoding::Base64Encode(file_hash));
  418. properties->SetString(kPayloadPropertyMetadataHash,
  419. brillo::data_encoding::Base64Encode(metadata_hash));
  420. return true;
  421. }
  422. } // namespace chromeos_update_engine