crx_creator.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/crx_file/crx_creator.h"
  5. #include "base/files/file.h"
  6. #include "base/files/file_path.h"
  7. #include "components/crx_file/crx3.pb.h"
  8. #include "components/crx_file/crx_file.h"
  9. #include "crypto/rsa_private_key.h"
  10. #include "crypto/sha2.h"
  11. #include "crypto/signature_creator.h"
  12. namespace crx_file {
  13. namespace {
  14. std::string GetCrxId(const std::string& key) {
  15. uint8_t hash[16] = {}; // CRX IDs are 16 bytes long.
  16. crypto::SHA256HashString(key, hash, sizeof(hash));
  17. static_assert(sizeof(char) == sizeof(uint8_t), "Unsupported char size.");
  18. return std::string(reinterpret_cast<char*>(hash), sizeof(hash));
  19. }
  20. // Read to the end of the file, updating the signer.
  21. CreatorResult ReadAndSignArchive(base::File* file,
  22. crypto::SignatureCreator* signer,
  23. std::vector<uint8_t>* signature) {
  24. uint8_t buffer[1 << 12] = {};
  25. int read = 0;
  26. static_assert(sizeof(char) == sizeof(uint8_t), "Unsupported char size.");
  27. while ((read = file->ReadAtCurrentPos(reinterpret_cast<char*>(buffer),
  28. std::size(buffer))) > 0) {
  29. if (!signer->Update(buffer, read))
  30. return CreatorResult::ERROR_SIGNING_FAILURE;
  31. }
  32. if (read < 0)
  33. return CreatorResult::ERROR_SIGNING_FAILURE;
  34. return signer->Final(signature) ? CreatorResult::OK
  35. : CreatorResult::ERROR_SIGNING_FAILURE;
  36. }
  37. bool WriteBuffer(base::File* file, const char buffer[], int len) {
  38. return file->WriteAtCurrentPos(buffer, len) == len;
  39. }
  40. bool WriteArchive(base::File* out, base::File* in) {
  41. char buffer[1 << 12] = {};
  42. int read = 0;
  43. in->Seek(base::File::Whence::FROM_BEGIN, 0);
  44. while ((read = in->ReadAtCurrentPos(buffer, std::size(buffer))) > 0) {
  45. if (out->WriteAtCurrentPos(buffer, read) != read)
  46. return false;
  47. }
  48. return read == 0;
  49. }
  50. CreatorResult SignArchiveAndCreateHeader(const base::FilePath& output_path,
  51. base::File* file,
  52. crypto::RSAPrivateKey* signing_key,
  53. CrxFileHeader* header) {
  54. // Get the public key.
  55. std::vector<uint8_t> public_key;
  56. signing_key->ExportPublicKey(&public_key);
  57. const std::string public_key_str(public_key.begin(), public_key.end());
  58. // Assemble SignedData section.
  59. SignedData signed_header_data;
  60. signed_header_data.set_crx_id(GetCrxId(public_key_str));
  61. const std::string signed_header_data_str =
  62. signed_header_data.SerializeAsString();
  63. const int signed_header_size = signed_header_data_str.size();
  64. const uint8_t signed_header_size_octets[] = {
  65. static_cast<uint8_t>(signed_header_size),
  66. static_cast<uint8_t>(signed_header_size >> 8),
  67. static_cast<uint8_t>(signed_header_size >> 16),
  68. static_cast<uint8_t>(signed_header_size >> 24)};
  69. // Create a signer, init with purpose, SignedData length, run SignedData
  70. // through, run ZIP through.
  71. auto signer = crypto::SignatureCreator::Create(
  72. signing_key, crypto::SignatureCreator::HashAlgorithm::SHA256);
  73. signer->Update(reinterpret_cast<const uint8_t*>(kSignatureContext),
  74. std::size(kSignatureContext));
  75. signer->Update(signed_header_size_octets,
  76. std::size(signed_header_size_octets));
  77. signer->Update(
  78. reinterpret_cast<const uint8_t*>(signed_header_data_str.data()),
  79. signed_header_data_str.size());
  80. if (!file->IsValid())
  81. return CreatorResult::ERROR_FILE_NOT_READABLE;
  82. std::vector<uint8_t> signature;
  83. const CreatorResult signing_result =
  84. ReadAndSignArchive(file, signer.get(), &signature);
  85. if (signing_result != CreatorResult::OK)
  86. return signing_result;
  87. AsymmetricKeyProof* proof = header->add_sha256_with_rsa();
  88. proof->set_public_key(public_key_str);
  89. proof->set_signature(std::string(signature.begin(), signature.end()));
  90. header->set_signed_header_data(signed_header_data_str);
  91. return CreatorResult::OK;
  92. }
  93. CreatorResult WriteCRX(const CrxFileHeader& header,
  94. const base::FilePath& output_path,
  95. base::File* file) {
  96. const std::string header_str = header.SerializeAsString();
  97. const int header_size = header_str.size();
  98. const uint8_t header_size_octets[] = {
  99. static_cast<uint8_t>(header_size), static_cast<uint8_t>(header_size >> 8),
  100. static_cast<uint8_t>(header_size >> 16),
  101. static_cast<uint8_t>(header_size >> 24)};
  102. const uint8_t format_version_octets[] = {3, 0, 0, 0};
  103. base::File crx(output_path,
  104. base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  105. if (!crx.IsValid())
  106. return CreatorResult::ERROR_FILE_NOT_WRITABLE;
  107. static_assert(sizeof(char) == sizeof(uint8_t), "Unsupported char size.");
  108. if (!WriteBuffer(&crx, kCrxFileHeaderMagic, kCrxFileHeaderMagicSize) ||
  109. !WriteBuffer(&crx, reinterpret_cast<const char*>(format_version_octets),
  110. std::size(format_version_octets)) ||
  111. !WriteBuffer(&crx, reinterpret_cast<const char*>(header_size_octets),
  112. std::size(header_size_octets)) ||
  113. !WriteBuffer(&crx, header_str.c_str(), header_str.length()) ||
  114. !WriteArchive(&crx, file)) {
  115. return CreatorResult::ERROR_FILE_WRITE_FAILURE;
  116. }
  117. return CreatorResult::OK;
  118. }
  119. } // namespace
  120. CreatorResult CreateCrxWithVerifiedContentsInHeader(
  121. const base::FilePath& output_path,
  122. const base::FilePath& zip_path,
  123. crypto::RSAPrivateKey* signing_key,
  124. const std::string& verified_contents) {
  125. CrxFileHeader header;
  126. base::File file(zip_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  127. const CreatorResult signing_result =
  128. SignArchiveAndCreateHeader(output_path, &file, signing_key, &header);
  129. if (signing_result != CreatorResult::OK)
  130. return signing_result;
  131. // Inject the verified contents into the header.
  132. header.set_verified_contents(verified_contents);
  133. const CreatorResult result = WriteCRX(header, output_path, &file);
  134. return result;
  135. }
  136. CreatorResult Create(const base::FilePath& output_path,
  137. const base::FilePath& zip_path,
  138. crypto::RSAPrivateKey* signing_key) {
  139. CrxFileHeader header;
  140. base::File file(zip_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  141. const CreatorResult signing_result =
  142. SignArchiveAndCreateHeader(output_path, &file, signing_key, &header);
  143. if (signing_result != CreatorResult::OK)
  144. return signing_result;
  145. const CreatorResult result = WriteCRX(header, output_path, &file);
  146. return result;
  147. }
  148. } // namespace crx_file