[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / crx_file / crx_creator.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_creator.h"
6
7 #include "base/files/file.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "components/crx_file/crx3.pb.h"
11 #include "components/crx_file/crx_file.h"
12 #include "crypto/rsa_private_key.h"
13 #include "crypto/sha2.h"
14 #include "crypto/signature_creator.h"
15
16 namespace crx_file {
17
18 namespace {
19
20 std::string GetCrxId(const std::string& key) {
21   uint8_t hash[16] = {};  // CRX IDs are 16 bytes long.
22   crypto::SHA256HashString(key, hash, sizeof(hash));
23   static_assert(sizeof(char) == sizeof(uint8_t), "Unsupported char size.");
24   return std::string(reinterpret_cast<char*>(hash), sizeof(hash));
25 }
26
27 // Read to the end of the file, updating the signer.
28 CreatorResult ReadAndSignArchive(base::File* file,
29                                  crypto::SignatureCreator* signer,
30                                  std::vector<uint8_t>* signature) {
31   uint8_t buffer[1 << 12] = {};
32   int read = 0;
33   static_assert(sizeof(char) == sizeof(uint8_t), "Unsupported char size.");
34   while ((read = file->ReadAtCurrentPos(reinterpret_cast<char*>(buffer),
35                                         std::size(buffer))) > 0) {
36     if (!signer->Update(buffer, read))
37       return CreatorResult::ERROR_SIGNING_FAILURE;
38   }
39   if (read < 0)
40     return CreatorResult::ERROR_SIGNING_FAILURE;
41   return signer->Final(signature) ? CreatorResult::OK
42                                   : CreatorResult::ERROR_SIGNING_FAILURE;
43 }
44
45 bool WriteBuffer(base::File* file, const char buffer[], int len) {
46   return file->WriteAtCurrentPos(buffer, len) == len;
47 }
48
49 bool WriteArchive(base::File* out, base::File* in) {
50   char buffer[1 << 12] = {};
51   int read = 0;
52   in->Seek(base::File::Whence::FROM_BEGIN, 0);
53   while ((read = in->ReadAtCurrentPos(buffer, std::size(buffer))) > 0) {
54     if (out->WriteAtCurrentPos(buffer, read) != read)
55       return false;
56   }
57   return read == 0;
58 }
59
60 CreatorResult SignArchiveAndCreateHeader(const base::FilePath& output_path,
61                                          base::File* file,
62                                          crypto::RSAPrivateKey* signing_key,
63                                          CrxFileHeader* header) {
64   // Get the public key.
65   std::vector<uint8_t> public_key;
66   signing_key->ExportPublicKey(&public_key);
67   const std::string public_key_str(public_key.begin(), public_key.end());
68
69   // Assemble SignedData section.
70   SignedData signed_header_data;
71   signed_header_data.set_crx_id(GetCrxId(public_key_str));
72   const std::string signed_header_data_str =
73       signed_header_data.SerializeAsString();
74   const int signed_header_size = signed_header_data_str.size();
75   const uint8_t signed_header_size_octets[] = {
76       static_cast<uint8_t>(signed_header_size),
77       static_cast<uint8_t>(signed_header_size >> 8),
78       static_cast<uint8_t>(signed_header_size >> 16),
79       static_cast<uint8_t>(signed_header_size >> 24)};
80
81   // Create a signer, init with purpose, SignedData length, run SignedData
82   // through, run ZIP through.
83   auto signer = crypto::SignatureCreator::Create(
84       signing_key, crypto::SignatureCreator::HashAlgorithm::SHA256);
85   signer->Update(reinterpret_cast<const uint8_t*>(kSignatureContext),
86                  std::size(kSignatureContext));
87   signer->Update(signed_header_size_octets,
88                  std::size(signed_header_size_octets));
89   signer->Update(
90       reinterpret_cast<const uint8_t*>(signed_header_data_str.data()),
91       signed_header_data_str.size());
92
93   if (!file->IsValid())
94     return CreatorResult::ERROR_FILE_NOT_READABLE;
95   std::vector<uint8_t> signature;
96   const CreatorResult signing_result =
97       ReadAndSignArchive(file, signer.get(), &signature);
98   if (signing_result != CreatorResult::OK)
99     return signing_result;
100   AsymmetricKeyProof* proof = header->add_sha256_with_rsa();
101   proof->set_public_key(public_key_str);
102   proof->set_signature(std::string(signature.begin(), signature.end()));
103   header->set_signed_header_data(signed_header_data_str);
104   return CreatorResult::OK;
105 }
106
107 CreatorResult WriteCRX(const CrxFileHeader& header,
108                        const base::FilePath& output_path,
109                        base::File* file) {
110   const std::string header_str = header.SerializeAsString();
111   const int header_size = header_str.size();
112   const uint8_t header_size_octets[] = {
113       static_cast<uint8_t>(header_size), static_cast<uint8_t>(header_size >> 8),
114       static_cast<uint8_t>(header_size >> 16),
115       static_cast<uint8_t>(header_size >> 24)};
116
117   const uint8_t format_version_octets[] = {3, 0, 0, 0};
118   base::File crx(output_path,
119                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
120   if (!crx.IsValid())
121     return CreatorResult::ERROR_FILE_NOT_WRITABLE;
122   static_assert(sizeof(char) == sizeof(uint8_t), "Unsupported char size.");
123   if (!WriteBuffer(&crx, kCrxFileHeaderMagic, kCrxFileHeaderMagicSize) ||
124       !WriteBuffer(&crx, reinterpret_cast<const char*>(format_version_octets),
125                    std::size(format_version_octets)) ||
126       !WriteBuffer(&crx, reinterpret_cast<const char*>(header_size_octets),
127                    std::size(header_size_octets)) ||
128       !WriteBuffer(&crx, header_str.c_str(), header_str.length()) ||
129       !WriteArchive(&crx, file)) {
130     return CreatorResult::ERROR_FILE_WRITE_FAILURE;
131   }
132   return CreatorResult::OK;
133 }
134
135 }  // namespace
136
137 CreatorResult CreateCrxWithVerifiedContentsInHeader(
138     const base::FilePath& output_path,
139     const base::FilePath& zip_path,
140     crypto::RSAPrivateKey* signing_key,
141     const std::string& verified_contents) {
142   CrxFileHeader header;
143   base::File file(zip_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
144                                 base::File::FLAG_WIN_SHARE_DELETE);
145   PLOG_IF(ERROR, !file.IsValid())
146       << "Failed to open " << zip_path << ": " << file.error_details();
147   const CreatorResult signing_result =
148       SignArchiveAndCreateHeader(output_path, &file, signing_key, &header);
149   if (signing_result != CreatorResult::OK)
150     return signing_result;
151
152   // Inject the verified contents into the header.
153   header.set_verified_contents(verified_contents);
154   const CreatorResult result = WriteCRX(header, output_path, &file);
155   return result;
156 }
157
158 CreatorResult Create(const base::FilePath& output_path,
159                      const base::FilePath& zip_path,
160                      crypto::RSAPrivateKey* signing_key) {
161   CrxFileHeader header;
162   base::File file(zip_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
163                                 base::File::FLAG_WIN_SHARE_DELETE);
164   PLOG_IF(ERROR, !file.IsValid())
165       << "Failed to open " << zip_path << ": " << file.error_details();
166   const CreatorResult signing_result =
167       SignArchiveAndCreateHeader(output_path, &file, signing_key, &header);
168   if (signing_result != CreatorResult::OK)
169     return signing_result;
170
171   const CreatorResult result = WriteCRX(header, output_path, &file);
172   return result;
173 }
174
175 }  // namespace crx_file