Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: net/tools/domain_security_preload_generator/preloaded_state_generator.cc

Issue 2551153003: Add static domain security state generator tool. (Closed)
Patch Set: fix base64 issue and accidental replace. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016 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
5 #include "net/tools/domain_security_preload_generator/preloaded_state_generator. h"
6
7 #include <iostream>
8
9 #include <string>
10
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "net/tools/domain_security_preload_generator/cert_util.h"
14 #include "net/tools/domain_security_preload_generator/huffman/huffman_frequency_ tracker.h"
15 #include "net/tools/domain_security_preload_generator/spki_hash.h"
16
17 namespace net {
18
19 namespace {
20
21 static const char* kNewLine = "\n";
agl 2016/12/06 18:51:36 ditto about [] vs *.
martijnc 2016/12/07 22:37:54 Done.
22 static const char* kIndent = " ";
23
24 std::string FormatSPKIName(const std::string& name) {
25 return "kSPKIHash_" + name;
26 }
27
28 std::string FormatAcceptedKeyName(const std::string& name) {
29 return "k" + name + "AcceptableCerts";
30 }
31
32 std::string FormatRejectedKeyName(const std::string& name) {
33 return "k" + name + "RejectedCerts";
34 }
35
36 std::string FormatReportURIName(const std::string& name) {
37 return "k" + name + "ReportURI";
38 }
39
40 std::string FormatVectorAsArray(const std::vector<uint8_t>& bytes) {
41 std::string output = "{";
42 output.append(kNewLine);
43 output.append(kIndent);
44 output.append(kIndent);
45
46 size_t bytes_on_current_line = 0;
47
48 for (size_t i = 0; i < bytes.size(); ++i) {
49 base::StringAppendF(&output, "0x%02x,", bytes[i]);
50
51 bytes_on_current_line++;
52 if (bytes_on_current_line >= 12 && (i + 1) < bytes.size()) {
agl 2016/12/06 18:51:36 no need for parens around |i + 1|.
martijnc 2016/12/07 22:37:54 Done.
53 output.append(kNewLine);
54 output.append(kIndent);
55 output.append(kIndent);
56
57 bytes_on_current_line = 0;
58 } else if ((i + 1) < bytes.size()) {
agl 2016/12/06 18:51:36 no need for parens around |i + 1|.
martijnc 2016/12/07 22:37:54 Done.
59 output.append(" ");
60 }
61 }
62
63 output.append(kNewLine);
64 output.append("}");
65
66 return output;
67 }
68
69 std::string WritePinsetList(const std::string& name,
70 const std::vector<std::string>& pins) {
71 std::string output = "static const char* const " + name + "[] = {";
72 output.append(kNewLine);
73
74 for (const auto& pin_name : pins) {
75 output.append(kIndent);
76 output.append(kIndent);
77 output.append(FormatSPKIName(pin_name));
78 output.append(",");
79 output.append(kNewLine);
80 }
81
82 output.append(kIndent);
83 output.append(kIndent);
84 output.append("NULL,");
85 output.append(kNewLine);
86 output.append("};");
87
88 return output;
89 }
90
91 HuffmanRepresentationTable ApproximateHuffman(
92 const DomainSecurityEntries& entries) {
93 HuffmanFrequencyTracker tracker;
94 for (const auto& entry : entries) {
95 for (const auto& c : entry->hostname()) {
96 tracker.RecordUsage(c);
97 }
98
99 tracker.RecordUsage(TrieWriter::kTerminalValue);
100 tracker.RecordUsage(TrieWriter::kEndOfTableValue);
101 }
102
103 return tracker.ToHuffmanRepresentationTable();
104 }
105
106 } // namespace
107
108 PreloadedStateGenerator::PreloadedStateGenerator() {}
109
110 PreloadedStateGenerator::~PreloadedStateGenerator() {}
111
112 std::string PreloadedStateGenerator::Generate(
113 const std::string& preload_template,
114 const DomainSecurityEntries& entries,
115 const DomainIDList& domain_ids,
116 const Pinsets& pinsets,
117 bool verbose) {
118 template_.reset(new Template(preload_template));
119
120 NameIDMap domain_ids_map;
121 ProcessDomainIds(domain_ids, &domain_ids_map);
122
123 ProcessSPKIHashes(pinsets);
124
125 NameIDMap expect_ct_report_uri_map;
126 ProcessExpectCTURIs(entries, &expect_ct_report_uri_map);
127
128 NameIDMap expect_staple_report_uri_map;
129 ProcessExpectStapleURIs(entries, &expect_staple_report_uri_map);
130
131 NameIDMap pinsets_map;
132 ProcessPinsets(pinsets, &pinsets_map);
133
134 HuffmanRepresentationTable table = ApproximateHuffman(entries);
135 HuffmanFrequencyTracker tracker;
136 TrieWriter writer(table, domain_ids_map, expect_ct_report_uri_map,
137 expect_staple_report_uri_map, pinsets_map, &tracker);
138 writer.WriteEntries(entries);
139 uint32_t initial_length = writer.position();
140
141 HuffmanRepresentationTable optimal_table =
142 tracker.ToHuffmanRepresentationTable();
143 TrieWriter new_writer(optimal_table, domain_ids_map, expect_ct_report_uri_map,
144 expect_staple_report_uri_map, pinsets_map, nullptr);
145
146 int root_position = new_writer.WriteEntries(entries);
147 uint32_t new_length = new_writer.position();
148
149 std::vector<uint8_t> huffman_tree = tracker.AsVector();
150
151 new_writer.close();
152
153 template_->ReplaceTag("HUFFMAN_TREE", FormatVectorAsArray(huffman_tree));
154 template_->ReplaceTag("HSTS_TRIE", FormatVectorAsArray(new_writer.bytes()));
155
156 template_->ReplaceTag("HSTS_TRIE_BITS", std::to_string(new_length));
157 template_->ReplaceTag("HSTS_TRIE_ROOT", std::to_string(root_position));
158
159 if (verbose) {
160 std::cout << "Saved " << std::to_string(initial_length - new_length)
161 << " bits by using accurate Huffman counts." << std::endl;
162 std::cout << "Bit length " << std::to_string(new_length) << std::endl;
163 std::cout << "Root position " << std::to_string(root_position) << std::endl;
164 }
165
166 return template_->GetOutput();
167 }
168
169 void PreloadedStateGenerator::ProcessDomainIds(const DomainIDList& domain_ids,
170 NameIDMap* map) {
171 DCHECK(template_.get());
172
173 std::string output = "{";
174 output.append(kNewLine);
175
176 for (size_t i = 0; i < domain_ids.size(); ++i) {
177 const std::string& current = domain_ids.at(i);
178 output.append(kIndent);
179 output.append("DOMAIN_" + current + ",");
180 output.append(kNewLine);
181
182 map->insert(NameIDPair(current, i));
183 }
184
185 output.append(kIndent);
186 output.append("// Boundary value for UMA_HISTOGRAM_ENUMERATION.");
187 output.append(kNewLine);
188 output.append(kIndent);
189 output.append("DOMAIN_NUM_EVENTS,");
190 output.append(kNewLine);
191 output.append("}");
192
193 template_->ReplaceTag("DOMAIN_IDS", output);
194 }
195
196 void PreloadedStateGenerator::ProcessSPKIHashes(const Pinsets& pinset) {
197 DCHECK(template_.get());
198
199 std::string output;
200
201 const SPKIHashMap& hashes = pinset.spki_hashes();
202 for (const auto& current : hashes) {
203 const std::string& name = current.first;
204 const SPKIHash& hash = current.second;
205
206 output.append("static const char " + FormatSPKIName(name) + "[] =");
207 output.append(kNewLine);
208
209 for (size_t i = 0; i < hash.size() / 16; ++i) {
210 output.append(kIndent);
211 output.append(kIndent);
212 output.append("\"");
213
214 for (size_t j = i * 16; j < ((i + 1) * 16); ++j) {
215 base::StringAppendF(&output, "\\x%02x", hash.data()[j]);
216 }
217
218 output.append("\"");
219 if (i + 1 == hash.size() / 16) {
220 output.append(";");
221 }
222 output.append(kNewLine);
223 }
224
225 output.append(kNewLine);
226 }
227
228 base::TrimString(output, kNewLine, &output);
229 template_->ReplaceTag("SPKI_HASHES", output);
230 }
231
232 void PreloadedStateGenerator::ProcessExpectCTURIs(
233 const DomainSecurityEntries& entries,
234 NameIDMap* expect_ct_report_uri_map) {
235 std::string output = "{";
236 output.append(kNewLine);
237
238 for (const auto& entry : entries) {
239 const std::string& url = entry->expect_ct_report_uri();
240 if (entry->expect_ct() && url.size() &&
241 expect_ct_report_uri_map->find(url) ==
242 expect_ct_report_uri_map->cend()) {
243 output.append(kIndent);
244 output.append(kIndent);
245 output.append("\"" + entry->expect_ct_report_uri() + "\",");
246 output.append(kNewLine);
247
248 expect_ct_report_uri_map->insert(NameIDPair(
249 entry->expect_ct_report_uri(), expect_ct_report_uri_map->size()));
250 }
251 }
252
253 output.append("}");
254 template_->ReplaceTag("EXPECT_CT_REPORT_URIS", output);
255 }
256
257 void PreloadedStateGenerator::ProcessExpectStapleURIs(
258 const DomainSecurityEntries& entries,
259 NameIDMap* expect_staple_report_uri_map) {
260 std::string output = "{";
261 output.append(kNewLine);
262
263 for (const auto& entry : entries) {
264 const std::string& url = entry->expect_staple_report_uri();
265 if (entry->expect_staple() && url.size() &&
266 expect_staple_report_uri_map->find(url) ==
267 expect_staple_report_uri_map->cend()) {
268 output.append(kIndent);
269 output.append(kIndent);
270 output.append("\"" + entry->expect_staple_report_uri() + "\",");
271 output.append(kNewLine);
272
273 expect_staple_report_uri_map->insert(
274 NameIDPair(entry->expect_staple_report_uri(),
275 expect_staple_report_uri_map->size()));
276 }
277 }
278
279 output.append("}");
280 template_->ReplaceTag("EXPECT_STAPLE_REPORT_URIS", output);
281 }
282
283 void PreloadedStateGenerator::ProcessPinsets(const Pinsets& pinset,
284 NameIDMap* pinset_map) {
285 std::string certs_output;
286 std::string pinsets_output = "{";
287 pinsets_output.append(kNewLine);
288
289 const PinsetMap& pinsets = pinset.pinsets();
290 for (const auto& current : pinsets) {
291 const std::unique_ptr<Pinset>& pinset = current.second;
292 std::string uppercased_name = pinset->name();
293 uppercased_name[0] = base::ToUpperASCII(uppercased_name[0]);
294
295 const std::string& accepted_pins_names =
296 FormatAcceptedKeyName(uppercased_name);
297 certs_output.append(
298 WritePinsetList(accepted_pins_names, pinset->static_spki_hashes()));
299 certs_output.append(kNewLine);
300
301 std::string rejected_pins_names = "kNoRejectedPublicKeys";
302 if (pinset->bad_static_spki_hashes().size()) {
303 rejected_pins_names = FormatRejectedKeyName(uppercased_name);
304 certs_output.append(WritePinsetList(rejected_pins_names,
305 pinset->bad_static_spki_hashes()));
306 certs_output.append(kNewLine);
307 }
308
309 std::string report_uri = "kNoReportURI";
310 if (pinset->report_uri().size()) {
311 report_uri = FormatReportURIName(uppercased_name);
312 certs_output.append("static const char " + report_uri + "[] = ");
313 certs_output.append("\"");
314 certs_output.append(pinset->report_uri());
315 certs_output.append("\";");
316 certs_output.append(kNewLine);
317 }
318 certs_output.append(kNewLine);
319
320 pinsets_output.append(kIndent);
321 pinsets_output.append(kIndent);
322 pinsets_output.append("{" + accepted_pins_names + ", " +
323 rejected_pins_names + ", " + report_uri + "},");
324 pinsets_output.append(kNewLine);
325
326 pinset_map->insert(NameIDPair(pinset->name(), pinset_map->size()));
327 }
328
329 pinsets_output.append("}");
330
331 base::TrimString(certs_output, kNewLine, &certs_output);
332
333 template_->ReplaceTag("ACCEPTABLE_CERTS", certs_output);
334 template_->ReplaceTag("PINSETS", pinsets_output);
335 }
336
337 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698