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