crx_verifier.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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_verifier.h"
  5. #include <climits>
  6. #include <cstring>
  7. #include <iterator>
  8. #include <memory>
  9. #include <set>
  10. #include <utility>
  11. #include "base/base64.h"
  12. #include "base/bind.h"
  13. #include "base/callback.h"
  14. #include "base/files/file.h"
  15. #include "base/files/file_path.h"
  16. #include "base/numerics/safe_conversions.h"
  17. #include "base/strings/string_number_conversions.h"
  18. #include "components/crx_file/crx3.pb.h"
  19. #include "components/crx_file/crx_file.h"
  20. #include "components/crx_file/id_util.h"
  21. #include "crypto/secure_hash.h"
  22. #include "crypto/secure_util.h"
  23. #include "crypto/sha2.h"
  24. #include "crypto/signature_verifier.h"
  25. #include "third_party/abseil-cpp/absl/types/optional.h"
  26. namespace crx_file {
  27. namespace {
  28. // The SHA256 hash of the DER SPKI "ecdsa_2017_public" Crx3 key.
  29. constexpr uint8_t kPublisherKeyHash[] = {
  30. 0x61, 0xf7, 0xf2, 0xa6, 0xbf, 0xcf, 0x74, 0xcd, 0x0b, 0xc1, 0xfe,
  31. 0x24, 0x97, 0xcc, 0x9b, 0x04, 0x25, 0x4c, 0x65, 0x8f, 0x79, 0xf2,
  32. 0x14, 0x53, 0x92, 0x86, 0x7e, 0xa8, 0x36, 0x63, 0x67, 0xcf};
  33. // The SHA256 hash of the DER SPKI "ecdsa_2017_public" Crx3 test key.
  34. constexpr uint8_t kPublisherTestKeyHash[] = {
  35. 0x6c, 0x46, 0x41, 0x3b, 0x00, 0xd0, 0xfa, 0x0e, 0x72, 0xc8, 0xd2,
  36. 0x5f, 0x64, 0xf3, 0xa6, 0x17, 0x03, 0x0d, 0xde, 0x21, 0x61, 0xbe,
  37. 0xb7, 0x95, 0x91, 0x95, 0x83, 0x68, 0x12, 0xe9, 0x78, 0x1e};
  38. using VerifierCollection =
  39. std::vector<std::unique_ptr<crypto::SignatureVerifier>>;
  40. using RepeatedProof = google::protobuf::RepeatedPtrField<AsymmetricKeyProof>;
  41. int ReadAndHashBuffer(uint8_t* buffer,
  42. int length,
  43. base::File* file,
  44. crypto::SecureHash* hash) {
  45. static_assert(sizeof(char) == sizeof(uint8_t), "Unsupported char size.");
  46. int read = file->ReadAtCurrentPos(reinterpret_cast<char*>(buffer), length);
  47. if (read > 0)
  48. hash->Update(buffer, read);
  49. return read;
  50. }
  51. // Returns UINT32_MAX in the case of an unexpected EOF or read error, else
  52. // returns the read uint32.
  53. uint32_t ReadAndHashLittleEndianUInt32(base::File* file,
  54. crypto::SecureHash* hash) {
  55. uint8_t buffer[4] = {};
  56. if (ReadAndHashBuffer(buffer, 4, file, hash) != 4)
  57. return UINT32_MAX;
  58. return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
  59. }
  60. // Read to the end of the file, updating the hash and all verifiers.
  61. bool ReadHashAndVerifyArchive(base::File* file,
  62. crypto::SecureHash* hash,
  63. const VerifierCollection& verifiers) {
  64. uint8_t buffer[1 << 12] = {};
  65. size_t len = 0;
  66. while ((len = ReadAndHashBuffer(buffer, std::size(buffer), file, hash)) > 0) {
  67. for (auto& verifier : verifiers)
  68. verifier->VerifyUpdate(base::make_span(buffer, len));
  69. }
  70. for (auto& verifier : verifiers) {
  71. if (!verifier->VerifyFinal())
  72. return false;
  73. }
  74. return len == 0;
  75. }
  76. // The remaining contents of a Crx3 file are [header-size][header][archive].
  77. // [header] is an encoded protocol buffer and contains both a signed and
  78. // unsigned section. The unsigned section contains a set of key/signature pairs,
  79. // and the signed section is the encoding of another protocol buffer. All
  80. // signatures cover [prefix][signed-header-size][signed-header][archive].
  81. VerifierResult VerifyCrx3(
  82. base::File* file,
  83. crypto::SecureHash* hash,
  84. const std::vector<std::vector<uint8_t>>& required_key_hashes,
  85. std::string* public_key,
  86. std::string* crx_id,
  87. std::vector<uint8_t>* compressed_verified_contents,
  88. bool require_publisher_key,
  89. bool accept_publisher_test_key) {
  90. // Parse [header-size] and [header].
  91. int header_size =
  92. base::saturated_cast<int>(ReadAndHashLittleEndianUInt32(file, hash));
  93. if (header_size == INT_MAX)
  94. return VerifierResult::ERROR_HEADER_INVALID;
  95. std::vector<uint8_t> header_bytes(header_size);
  96. if (ReadAndHashBuffer(header_bytes.data(), header_size, file, hash) !=
  97. header_size) {
  98. return VerifierResult::ERROR_HEADER_INVALID;
  99. }
  100. CrxFileHeader header;
  101. if (!header.ParseFromArray(header_bytes.data(), header_size))
  102. return VerifierResult::ERROR_HEADER_INVALID;
  103. // Parse [verified_contents].
  104. if (header.has_verified_contents() && compressed_verified_contents) {
  105. const std::string& header_verified_contents(header.verified_contents());
  106. compressed_verified_contents->assign(header_verified_contents.begin(),
  107. header_verified_contents.end());
  108. }
  109. // Parse [signed-header].
  110. const std::string& signed_header_data_str = header.signed_header_data();
  111. SignedData signed_header_data;
  112. if (!signed_header_data.ParseFromString(signed_header_data_str))
  113. return VerifierResult::ERROR_HEADER_INVALID;
  114. const std::string& crx_id_encoded = signed_header_data.crx_id();
  115. const std::string declared_crx_id = id_util::GenerateIdFromHex(
  116. base::HexEncode(crx_id_encoded.data(), crx_id_encoded.size()));
  117. // Create a little-endian representation of [signed-header-size].
  118. const int signed_header_size = signed_header_data_str.size();
  119. const uint8_t header_size_octets[] = {
  120. static_cast<uint8_t>(signed_header_size),
  121. static_cast<uint8_t>(signed_header_size >> 8),
  122. static_cast<uint8_t>(signed_header_size >> 16),
  123. static_cast<uint8_t>(signed_header_size >> 24)};
  124. // Create a set of all required key hashes.
  125. std::set<std::vector<uint8_t>> required_key_set(required_key_hashes.begin(),
  126. required_key_hashes.end());
  127. using ProofFetcher = const RepeatedProof& (CrxFileHeader::*)() const;
  128. ProofFetcher rsa = &CrxFileHeader::sha256_with_rsa;
  129. ProofFetcher ecdsa = &CrxFileHeader::sha256_with_ecdsa;
  130. std::string public_key_bytes;
  131. VerifierCollection verifiers;
  132. verifiers.reserve(header.sha256_with_rsa_size() +
  133. header.sha256_with_ecdsa_size());
  134. const std::vector<
  135. std::pair<ProofFetcher, crypto::SignatureVerifier::SignatureAlgorithm>>
  136. proof_types = {
  137. std::make_pair(rsa, crypto::SignatureVerifier::RSA_PKCS1_SHA256),
  138. std::make_pair(ecdsa, crypto::SignatureVerifier::ECDSA_SHA256)};
  139. std::vector<uint8_t> publisher_key(std::begin(kPublisherKeyHash),
  140. std::end(kPublisherKeyHash));
  141. absl::optional<std::vector<uint8_t>> publisher_test_key;
  142. if (accept_publisher_test_key) {
  143. publisher_test_key.emplace(std::begin(kPublisherTestKeyHash),
  144. std::end(kPublisherTestKeyHash));
  145. }
  146. bool found_publisher_key = false;
  147. // Initialize all verifiers and update them with
  148. // [prefix][signed-header-size][signed-header].
  149. // Clear any elements of required_key_set that are encountered, and watch for
  150. // the developer key.
  151. for (const auto& proof_type : proof_types) {
  152. for (const auto& proof : (header.*proof_type.first)()) {
  153. const std::string& key = proof.public_key();
  154. const std::string& sig = proof.signature();
  155. if (id_util::GenerateId(key) == declared_crx_id)
  156. public_key_bytes = key;
  157. std::vector<uint8_t> key_hash(crypto::kSHA256Length);
  158. crypto::SHA256HashString(key, key_hash.data(), key_hash.size());
  159. required_key_set.erase(key_hash);
  160. DCHECK_EQ(accept_publisher_test_key, publisher_test_key.has_value());
  161. found_publisher_key =
  162. found_publisher_key || key_hash == publisher_key ||
  163. (accept_publisher_test_key && key_hash == *publisher_test_key);
  164. auto v = std::make_unique<crypto::SignatureVerifier>();
  165. static_assert(sizeof(unsigned char) == sizeof(uint8_t),
  166. "Unsupported char size.");
  167. if (!v->VerifyInit(proof_type.second,
  168. base::as_bytes(base::make_span(sig)),
  169. base::as_bytes(base::make_span(key))))
  170. return VerifierResult::ERROR_SIGNATURE_INITIALIZATION_FAILED;
  171. v->VerifyUpdate(base::as_bytes(base::make_span(kSignatureContext)));
  172. v->VerifyUpdate(header_size_octets);
  173. v->VerifyUpdate(base::as_bytes(base::make_span(signed_header_data_str)));
  174. verifiers.push_back(std::move(v));
  175. }
  176. }
  177. if (public_key_bytes.empty() || !required_key_set.empty())
  178. return VerifierResult::ERROR_REQUIRED_PROOF_MISSING;
  179. if (require_publisher_key && !found_publisher_key)
  180. return VerifierResult::ERROR_REQUIRED_PROOF_MISSING;
  181. // Update and finalize the verifiers with [archive].
  182. if (!ReadHashAndVerifyArchive(file, hash, verifiers))
  183. return VerifierResult::ERROR_SIGNATURE_VERIFICATION_FAILED;
  184. base::Base64Encode(public_key_bytes, public_key);
  185. *crx_id = declared_crx_id;
  186. return VerifierResult::OK_FULL;
  187. }
  188. } // namespace
  189. VerifierResult Verify(
  190. const base::FilePath& crx_path,
  191. const VerifierFormat& format,
  192. const std::vector<std::vector<uint8_t>>& required_key_hashes,
  193. const std::vector<uint8_t>& required_file_hash,
  194. std::string* public_key,
  195. std::string* crx_id,
  196. std::vector<uint8_t>* compressed_verified_contents) {
  197. std::string public_key_local;
  198. std::string crx_id_local;
  199. base::File file(crx_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  200. if (!file.IsValid())
  201. return VerifierResult::ERROR_FILE_NOT_READABLE;
  202. std::unique_ptr<crypto::SecureHash> file_hash =
  203. crypto::SecureHash::Create(crypto::SecureHash::SHA256);
  204. // Magic number.
  205. bool diff = false;
  206. char buffer[kCrxFileHeaderMagicSize] = {};
  207. if (file.ReadAtCurrentPos(buffer, kCrxFileHeaderMagicSize) !=
  208. kCrxFileHeaderMagicSize)
  209. return VerifierResult::ERROR_HEADER_INVALID;
  210. if (!strncmp(buffer, kCrxDiffFileHeaderMagic, kCrxFileHeaderMagicSize))
  211. diff = true;
  212. else if (strncmp(buffer, kCrxFileHeaderMagic, kCrxFileHeaderMagicSize))
  213. return VerifierResult::ERROR_HEADER_INVALID;
  214. file_hash->Update(buffer, sizeof(buffer));
  215. // Version number.
  216. const uint32_t version =
  217. ReadAndHashLittleEndianUInt32(&file, file_hash.get());
  218. VerifierResult result;
  219. if (version == 3) {
  220. bool require_publisher_key =
  221. format == VerifierFormat::CRX3_WITH_PUBLISHER_PROOF ||
  222. format == VerifierFormat::CRX3_WITH_TEST_PUBLISHER_PROOF;
  223. result = VerifyCrx3(
  224. &file, file_hash.get(), required_key_hashes, &public_key_local,
  225. &crx_id_local, compressed_verified_contents, require_publisher_key,
  226. format == VerifierFormat::CRX3_WITH_TEST_PUBLISHER_PROOF);
  227. } else {
  228. result = VerifierResult::ERROR_HEADER_INVALID;
  229. }
  230. if (result != VerifierResult::OK_FULL)
  231. return result;
  232. // Finalize file hash.
  233. uint8_t final_hash[crypto::kSHA256Length] = {};
  234. file_hash->Finish(final_hash, sizeof(final_hash));
  235. if (!required_file_hash.empty()) {
  236. if (required_file_hash.size() != crypto::kSHA256Length)
  237. return VerifierResult::ERROR_EXPECTED_HASH_INVALID;
  238. if (!crypto::SecureMemEqual(final_hash, required_file_hash.data(),
  239. crypto::kSHA256Length))
  240. return VerifierResult::ERROR_FILE_HASH_FAILED;
  241. }
  242. // All is well. Set the out-params and return.
  243. if (public_key)
  244. *public_key = public_key_local;
  245. if (crx_id)
  246. *crx_id = crx_id_local;
  247. return diff ? VerifierResult::OK_DELTA : VerifierResult::OK_FULL;
  248. }
  249. } // namespace crx_file