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

Side by Side Diff: net/tools/ct_mapper/write_results.cc

Issue 1238413004: Framework for iterating over certificates in CT database from Chromium code. (not for review) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make samples page work Created 3 years, 6 months 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
« no previous file with comments | « net/tools/ct_mapper/write_results.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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/ct_mapper/write_results.h"
6
7 #include <cstdio>
8 #include <iostream>
9 #include <map>
10 #include <memory>
11 #include <string>
12
13 #include "base/base64.h"
14 #include "base/command_line.h"
15 #include "base/files/file_util.h"
16 #include "base/format_macros.h"
17 #include "base/json/json_writer.h"
18 #include "base/logging.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/values.h"
24 #include "net/der/input.h"
25 #include "net/tools/ct_mapper/entry.h"
26 #include "net/tools/ct_mapper/metrics.h"
27
28 namespace net {
29 namespace {
30
31 // Wraps the lines of text to fit in |width| characters (not including the
32 // newline)
33 std::string FormatFixedColumn(const std::string& text, size_t width) {
34 std::string result;
35
36 size_t pos = 0;
37 while (pos < text.size()) {
38 size_t remaining = text.size() - pos;
39 size_t chunk_len = remaining < width ? remaining : width;
40 result += text.substr(pos, chunk_len) + "\n";
41 pos += chunk_len;
42 }
43
44 return result;
45 }
46
47 void WriteStringToFile(const std::string& data, const base::FilePath& path) {
48 CHECK_EQ(static_cast<int>(data.size()),
49 base::WriteFile(path, data.data(), data.size()));
50 }
51
52 std::string ExecCommand(const std::string& cmd) {
53 FILE* pipe = popen(cmd.c_str(), "r");
54
55 if (!pipe)
56 return "ERROR";
57
58 std::string result = "";
59 char buffer[256];
60 while (!feof(pipe)) {
61 if (fgets(buffer, sizeof(buffer), pipe) != NULL)
62 result += buffer;
63 }
64
65 pclose(pipe);
66 return result;
67 }
68
69 std::string ExecOpenSslCmd(const std::string& cmd, const der::Input& input) {
70 base::FilePath tmp_input_path;
71 CHECK(base::CreateTemporaryFile(&tmp_input_path));
72 WriteStringToFile(input.AsString(), tmp_input_path);
73
74 std::string result = ExecCommand(base::StringPrintf(
75 "%s -in \"%s\"", cmd.c_str(), tmp_input_path.value().c_str()));
76
77 CHECK(base::DeleteFile(tmp_input_path, false));
78
79 return result;
80 }
81
82 // Writes |cert| in PEM format. Which is to say something like:
83 //
84 // -----BEGIN CERTIFICATE-----
85 // gobbeldy gook in here here...
86 // -----END CERTIFICATE-----
87 std::string FormatCertificateAsPem(const net::der::Input& cert) {
88 std::string result;
89 result += "-----BEGIN CERTIFICATE-----\n";
90 const char* x = reinterpret_cast<const char*>(cert.UnsafeData());
91 std::string base64_encoded;
92 base::Base64Encode(base::StringPiece(x, cert.Length()), &base64_encoded);
93 result += FormatFixedColumn(base64_encoded, 75);
94 result += "-----END CERTIFICATE-----\n";
95 return result;
96 }
97
98 std::string FormatSampleAsPem(const Sample& sample) {
99 // Make a single vector with all the certificates, for simplicity.
100 const std::vector<der::Input>& chain = sample.certs;
101
102 std::string data;
103
104 for (size_t i = 0; i < chain.size(); ++i) {
105 const auto& cert = chain[i];
106 data += "\n\n";
107 data +=
108 base::StringPrintf("========= Cert%d =========\n", static_cast<int>(i));
109 data += ExecOpenSslCmd("openssl x509 -noout -text -inform DER", cert);
110 }
111
112 data += "\n";
113
114 data += "=====================================\n";
115 data += "Parsed data\n";
116 data += "=====================================\n";
117
118 for (size_t i = 0; i < chain.size(); ++i) {
119 const auto& cert = chain[i];
120 data += "\n\n";
121 data +=
122 base::StringPrintf("========= Cert%d =========\n", static_cast<int>(i));
123 data += ExecOpenSslCmd("openssl asn1parse -i -inform DER", cert);
124 }
125
126 data += "\n";
127 data += "=====================================\n";
128 data += "PEM data\n";
129 data += "=====================================\n";
130
131 for (size_t i = 0; i < chain.size(); ++i) {
132 const auto& cert = chain[i];
133 data += "\n\n";
134 data +=
135 base::StringPrintf("========= Cert%d =========\n", static_cast<int>(i));
136 data += FormatCertificateAsPem(cert);
137 }
138
139 return data;
140 }
141
142 base::FilePath GetSrcDir() {
143 // Assume that the current program is running in a subdirectory of "src". Keep
144 // descending until we find the src directory...
145
146 auto src_path = base::MakeAbsoluteFilePath(
147 base::CommandLine::ForCurrentProcess()->GetProgram());
148
149 while (src_path != src_path.DirName()) {
150 if (src_path.BaseName().value() == "src") {
151 return src_path;
152 }
153 src_path = src_path.DirName();
154 }
155
156 return base::FilePath();
157 }
158
159 void CopyStaticFile(const std::string& src_relative_path,
160 const base::FilePath& dest_dir) {
161 auto path = GetSrcDir().AppendASCII(src_relative_path);
162 CHECK(base::CopyFile(path, dest_dir.Append(path.BaseName())));
163 }
164
165 std::unique_ptr<base::ListValue> CreateListForSamples(
166 const std::vector<Sample>& samples,
167 size_t metrics_i,
168 size_t bucket_i,
169 const base::FilePath& dir_path) {
170 std::unique_ptr<base::ListValue> samples_list =
171 base::MakeUnique<base::ListValue>();
172
173 if (!samples.empty()) {
174 std::string samples_dir_name =
175 base::SizeTToString(metrics_i) + "-" + base::SizeTToString(bucket_i);
176
177 // Create a directory to hold all the samples for this bucket
178 base::FilePath samples_dir = dir_path.AppendASCII(samples_dir_name);
179 CHECK(base::CreateDirectory(samples_dir));
180
181 // Write all the samples into the bucket's directory.
182 for (size_t samples_i = 0; samples_i < samples.size(); ++samples_i) {
183 const auto& sample = samples[samples_i];
184 std::string data = FormatSampleAsPem(sample) + "\n\n";
185 std::string samples_relpath =
186 samples_dir_name + "/" + base::SizeTToString(samples_i);
187
188 if (sample.certs.size() == 1)
189 samples_relpath += ".cert";
190 else
191 samples_relpath += ".chain";
192
193 samples_relpath += ".txt";
194
195 WriteStringToFile(data, dir_path.AppendASCII(samples_relpath));
196 samples_list->AppendString(samples_relpath);
197 }
198 }
199
200 return samples_list;
201 }
202
203 std::unique_ptr<base::DictionaryValue> CreateDictForBucket(
204 const BucketValue& bucket,
205 const std::string& bucket_name,
206 size_t metrics_i,
207 size_t bucket_i,
208 const base::FilePath& dir_path) {
209 std::unique_ptr<base::DictionaryValue> bucket_dict =
210 base::MakeUnique<base::DictionaryValue>();
211
212 bucket_dict->SetString("name", bucket_name);
213 bucket_dict->SetDouble("total", bucket.total);
214
215 bucket_dict->Set("samples", CreateListForSamples(bucket.samples, metrics_i,
216 bucket_i, dir_path));
217
218 return bucket_dict;
219 }
220
221 std::unique_ptr<base::ListValue> CreateListForBuckets(
222 const MetricsItem::BucketMap& bucket_map,
223 size_t metrics_i,
224 const base::FilePath& dir_path) {
225 std::unique_ptr<base::ListValue> buckets_value =
226 base::MakeUnique<base::ListValue>();
227
228 size_t bucket_i = 0;
229 for (const auto& bucket_it : bucket_map) {
230 const auto& bucket = bucket_it.second;
231 buckets_value->Append(CreateDictForBucket(bucket, bucket_it.first,
232 metrics_i, bucket_i, dir_path));
233 bucket_i++;
234 }
235
236 return buckets_value;
237 }
238
239 std::unique_ptr<base::DictionaryValue> CreateDictForMetricsItem(
240 const std::string& name,
241 const MetricsItem& metrics_item,
242 size_t metrics_i,
243 const base::FilePath& dir_path) {
244 std::unique_ptr<base::DictionaryValue> metrics_dict =
245 base::MakeUnique<base::DictionaryValue>();
246
247 metrics_dict->SetString("name", name);
248 metrics_dict->SetDouble("total", metrics_item.total());
249 metrics_dict->Set("buckets", CreateListForBuckets(metrics_item.buckets(),
250 metrics_i, dir_path));
251 return metrics_dict;
252 }
253
254 std::unique_ptr<base::ListValue> CreateListForMetrics(
255 const Metrics& metrics,
256 const base::FilePath& dir_path) {
257 std::unique_ptr<base::ListValue> metrics_array_value =
258 base::MakeUnique<base::ListValue>();
259
260 size_t metrics_i = 0;
261 for (const auto& metrics_item_it : metrics.items()) {
262 const std::string& metrics_item_name = metrics_item_it.first;
263 const MetricsItem& metrics_item = metrics_item_it.second;
264
265 metrics_array_value->Append(CreateDictForMetricsItem(
266 metrics_item_name, metrics_item, metrics_i, dir_path));
267
268 metrics_i++;
269 }
270
271 return metrics_array_value;
272 }
273
274 } // namespace
275
276 void WriteResultsToDirectory(const Metrics& metrics,
277 const base::FilePath& dir_path) {
278 CopyStaticFile("net/tools/ct_mapper/index.html", dir_path);
279 CopyStaticFile("net/tools/ct_mapper/main.js", dir_path);
280
281 base::DictionaryValue results_dict;
282
283 results_dict.Set("metrics", CreateListForMetrics(metrics, dir_path));
284
285 // JSON-ify the overview information.
286 std::string json;
287 CHECK(base::JSONWriter::WriteWithOptions(
288 results_dict,
289 base::JSONWriter::OPTIONS_PRETTY_PRINT |
290 base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
291 &json));
292
293 // Use a .js file rather than a pure data file (since for data file would need
294 // to XHR it in... and Chrome doesn't let you XHR on file://. LAME.
295 WriteStringToFile("var g_data = " + json + ";",
296 dir_path.AppendASCII("data.js"));
297 }
298
299 } // namespace net
OLDNEW
« no previous file with comments | « net/tools/ct_mapper/write_results.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698