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

Side by Side Diff: net/extras/cert/cert_verifier_cache_persister.cc

Issue 2021433004: Cert - protobufs to serialize and deserialize CertVerifierCache. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@Add_support_for_walking_1999733002
Patch Set: Fix comments and more tests Created 4 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
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/extras/cert/cert_verifier_cache_persister.h"
6
7 #include <vector>
8
9 #include "base/logging.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/string_piece.h"
12 #include "base/time/time.h"
13 #include "net/base/hash_value.h"
14 #include "net/cert/caching_cert_verifier.h"
15 #include "net/cert/cert_type.h"
16 #include "net/cert/cert_verify_result.h"
17 #include "net/cert/x509_cert_types.h"
18 #include "net/cert/x509_certificate.h"
19 #include "net/extras/cert/proto/cert_verification.pb.h"
20
21 namespace net {
22
23 namespace {
24
25 typedef std::vector<std::string> CertVector;
26 typedef std::map<std::string, size_t> EncodedCertMap;
27
28 bool SerializeCertHandle(const X509Certificate::OSCertHandle& cert_handle,
29 CertVector* serialized_certs,
30 EncodedCertMap* encoded_certs,
Ryan Sleevi 2016/06/09 22:38:41 DESIGN: This seems like a memory-intensive seriali
ramant (doing other things) 2016/06/10 06:13:51 Excellent point. Fixed it. Done.
31 size_t* cert_number) {
32 std::string encoded;
33 if (!X509Certificate::GetDEREncoded(cert_handle, &encoded)) {
34 NOTREACHED();
35 return false;
36 }
37 EncodedCertMap::const_iterator it = encoded_certs->find(encoded);
Ryan Sleevi 2016/06/09 22:38:41 Improve documentation For example: // Determine i
ramant (doing other things) 2016/06/10 06:13:51 Done.
38 if (it != encoded_certs->end()) {
39 *cert_number = it->second;
40 } else {
41 serialized_certs->push_back(encoded);
42 *cert_number = serialized_certs->size() - 1;
43 encoded_certs->insert({encoded, *cert_number});
44 }
45 return true;
46 }
47
48 // Update |proto_certificate| with certificate number and updates
49 // |serialized_certs| with DER-encoded representation of certificate if the
50 // certicate is not in |serialized_certs|. Returns true if data is serialized
51 // correctly.
52 bool SerializeCertificate(const scoped_refptr<X509Certificate>& certificate,
Ryan Sleevi 2016/06/09 22:38:42 Pass as a naked pointer here since you're not reta
ramant (doing other things) 2016/06/10 06:13:52 Done.
53 CertVector* serialized_certs,
54 EncodedCertMap* encoded_certs,
55 CertVerificationCertificate* proto_certificate) {
56 size_t cert_number = 0;
57 if (!SerializeCertHandle(certificate->os_cert_handle(), serialized_certs,
58 encoded_certs, &cert_number)) {
59 NOTREACHED();
60 return false;
61 }
62 proto_certificate->add_cert_numbers(cert_number);
63 const X509Certificate::X509Certificate::OSCertHandles& intermediate_ca_certs =
64 certificate->GetIntermediateCertificates();
65 for (size_t i = 0; i < intermediate_ca_certs.size(); ++i) {
66 if (!SerializeCertHandle(intermediate_ca_certs[i], serialized_certs,
67 encoded_certs, &cert_number)) {
68 NOTREACHED();
69 return false;
70 }
71 proto_certificate->add_cert_numbers(cert_number);
72 }
73 return true;
74 }
75
76 // Returns deserialized certificate with the deserialized data from
77 // |proto_certificate|.
Ryan Sleevi 2016/06/09 22:38:41 This comment can be substantially improved // Des
ramant (doing other things) 2016/06/10 06:13:51 Done.
78 scoped_refptr<X509Certificate> DeserializeCertificate(
79 const CertVerificationCertificate& proto_certificate,
80 const CertVector& deserialized_der_certs) {
81 if (0 == proto_certificate.cert_numbers_size())
82 return nullptr;
83 std::vector<base::StringPiece> der_cert_pieces(
84 proto_certificate.cert_numbers_size());
85 for (int i = 0; i < proto_certificate.cert_numbers_size(); i++) {
86 size_t cert_number = proto_certificate.cert_numbers(i);
87 if (cert_number < deserialized_der_certs.size()) {
88 der_cert_pieces[i] =
89 base::StringPiece(deserialized_der_certs[cert_number]);
90 } else {
91 return nullptr;
Ryan Sleevi 2016/06/09 22:38:41 Do error handling first if (cert_number >= deseri
ramant (doing other things) 2016/06/10 06:13:51 Done.
92 }
93 }
94 return X509Certificate::CreateFromDERCertChain(der_cert_pieces);
95 }
96
97 // Update |proto_request_param| with RequestParams data from |params|.
Ryan Sleevi 2016/06/09 22:38:41 Again, documentation can be improved. // Serializ
ramant (doing other things) 2016/06/10 06:13:51 Done.
98 bool SerializeRequestParams(
99 const CertVerifier::RequestParams& params,
100 CertVector* serialized_certs,
101 EncodedCertMap* encoded_certs,
102 CertVerificationRequestParams* proto_request_param) {
103 CertVerificationCertificate* proto_certificate =
104 proto_request_param->mutable_certificate();
105 if (!SerializeCertificate(params.certificate(), serialized_certs,
106 encoded_certs, proto_certificate)) {
107 NOTREACHED();
108 return false;
109 }
110 proto_request_param->set_hostname(params.hostname());
111 proto_request_param->set_flags(params.flags());
112 proto_request_param->set_ocsp_response(params.ocsp_response());
113 for (const scoped_refptr<X509Certificate>& cert :
114 params.additional_trust_anchors()) {
115 proto_certificate = proto_request_param->add_additional_trust_anchors();
116 if (!SerializeCertificate(cert, serialized_certs, encoded_certs,
117 proto_certificate)) {
118 NOTREACHED();
119 return false;
120 }
121 }
122 return true;
123 }
124
125 // Update |proto_cached_result| with CachedResult data from |cache_iterator|.
126 // |serialized_certs| contains a list of unique DER-encoded representation of
127 // certificates.
Ryan Sleevi 2016/06/09 22:38:42 See above for how this wording can be improved.
ramant (doing other things) 2016/06/10 06:13:52 Done.
128 bool SerializeCachedResult(CachingCertVerifier::Iterator& cache_iterator,
129 CertVector* serialized_certs,
130 EncodedCertMap* encoded_certs,
131 CertVerificationCachedResult* proto_cached_result) {
132 proto_cached_result->set_error(cache_iterator.error());
133
134 // Serialize CertVerifyResult.
135 const CertVerifyResult& result = cache_iterator.verify_result();
136
137 CertVerificationResult* proto_result = proto_cached_result->mutable_result();
138 CertVerificationCertificate* proto_certificate =
139 proto_result->mutable_verified_cert();
140 if (!SerializeCertificate(result.verified_cert, serialized_certs,
141 encoded_certs, proto_certificate)) {
142 NOTREACHED();
143 return false;
144 }
145 proto_result->set_cert_status(result.cert_status);
146 proto_result->set_has_md2(result.has_md2);
147 proto_result->set_has_md4(result.has_md4);
148 proto_result->set_has_md5(result.has_md5);
149 proto_result->set_has_sha1(result.has_sha1);
150 proto_result->set_has_sha1_leaf(result.has_sha1_leaf);
151 for (const HashValue& value : result.public_key_hashes)
152 proto_result->add_public_key_hashes(value.ToString());
153 proto_result->set_is_issued_by_known_root(result.is_issued_by_known_root);
154 proto_result->set_is_issued_by_additional_trust_anchor(
155 result.is_issued_by_additional_trust_anchor);
156 proto_result->set_common_name_fallback_used(result.common_name_fallback_used);
157 return true;
158 }
159
160 // Update |error| and |result| with deserialized CachedResult data from
161 // |proto_cached_result|. Returns true if it is deserialized correctly.
162 bool DeserializeCachedResult(
163 const CertVerificationCachedResult& proto_cached_result,
164 const CertVector& deserialized_der_certs,
165 int* error,
166 CertVerifyResult* result) {
167 if (!proto_cached_result.has_error() || !proto_cached_result.has_result()) {
168 return false;
169 }
Ryan Sleevi 2016/06/09 22:38:41 no braces on single-line conditionals
ramant (doing other things) 2016/06/10 06:13:51 Done.
170
171 const CertVerificationResult& proto_result = proto_cached_result.result();
172 if (!proto_result.has_verified_cert() || !proto_result.has_cert_status()) {
Ryan Sleevi 2016/06/09 22:38:41 no braces on single-line conditionals
ramant (doing other things) 2016/06/10 06:13:52 Done.
173 return false;
174 }
175
176 *error = proto_cached_result.error();
177
178 result->verified_cert = DeserializeCertificate(proto_result.verified_cert(),
179 deserialized_der_certs);
180 if (!result->verified_cert || !result->verified_cert.get()) {
Ryan Sleevi 2016/06/09 22:38:41 no braces on single-line conditionals
ramant (doing other things) 2016/06/10 06:13:51 Done.
181 return false;
182 }
183
184 for (int i = 0; i < proto_result.public_key_hashes_size(); ++i) {
185 const ::std::string& public_key_hash = proto_result.public_key_hashes(i);
Ryan Sleevi 2016/06/09 22:38:41 Don't do ::std, just do std::
ramant (doing other things) 2016/06/10 06:13:52 Done.
186 HashValue hash;
187 if (!hash.FromString(public_key_hash))
188 return false;
189 result->public_key_hashes.push_back(hash);
190 }
191 result->cert_status = proto_result.cert_status();
192 result->has_md2 = proto_result.has_md2();
193 result->has_md4 = proto_result.has_md4();
194 result->has_md5 = proto_result.has_md5();
195 result->has_sha1 = proto_result.has_sha1();
196 result->has_sha1_leaf = proto_result.has_sha1_leaf();
197 result->is_issued_by_known_root = proto_result.is_issued_by_known_root();
198 result->is_issued_by_additional_trust_anchor =
199 proto_result.is_issued_by_additional_trust_anchor();
200 result->common_name_fallback_used = proto_result.common_name_fallback_used();
201 return true;
202 }
203
204 } // namespace
205
206 CertVerificationCache SerializeCertVerifierCache(
207 const CachingCertVerifier& verifier) {
208 base::TimeTicks start_time(base::TimeTicks::Now());
209 CertVerificationCache proto_cert_cache;
210 CertVector serialized_certs;
211 EncodedCertMap encoded_certs;
212
213 CachingCertVerifier::Iterator cache_iterator(verifier);
214 for (; cache_iterator.HasNext(); cache_iterator.Advance()) {
215 CertVerificationCacheEntry* proto_cache_entry =
216 proto_cert_cache.add_cache_entry();
217
218 CertVerificationRequestParams* proto_request_param =
219 proto_cache_entry->mutable_request_params();
220 if (!SerializeRequestParams(cache_iterator.params(), &serialized_certs,
221 &encoded_certs, proto_request_param)) {
222 NOTREACHED();
223 continue;
224 }
225
226 CertVerificationCachedResult* proto_cached_result =
227 proto_cache_entry->mutable_cached_result();
228 if (!SerializeCachedResult(cache_iterator, &serialized_certs,
229 &encoded_certs, proto_cached_result)) {
230 NOTREACHED();
231 continue;
232 }
233
234 proto_cache_entry->set_verification_time(
235 cache_iterator.verification_time().ToInternalValue());
236 }
237 for (const std::string& cert : serialized_certs)
238 proto_cert_cache.add_certs(cert);
239
240 UMA_HISTOGRAM_TIMES("Net.CertVerifierCachePersister.SerializeTime",
241 base::TimeTicks::Now() - start_time);
Ryan Sleevi 2016/06/09 22:38:41 Again, I think this is the wrong layer for histogr
ramant (doing other things) 2016/06/10 06:13:51 Done.
242 return proto_cert_cache;
243 }
244
245 bool DeserializeCertVerifierCache(const CertVerificationCache& proto_cert_cache,
246 CachingCertVerifier* verifier) {
247 base::TimeTicks load_cache_start_time = base::TimeTicks::Now();
248 CertVector deserialized_der_certs;
249
250 if (proto_cert_cache.certs_size() == 0u ||
251 proto_cert_cache.cache_entry_size() == 0u) {
252 return false;
253 }
254
255 for (int i = 0; i < proto_cert_cache.certs_size(); ++i)
Ryan Sleevi 2016/06/09 22:38:42 Seems like you can improve the comments throughout
ramant (doing other things) 2016/06/10 06:13:52 Done.
256 deserialized_der_certs.push_back(proto_cert_cache.certs(i));
257
258 bool detected_corrupted_data = false;
259 for (int i = 0; i < proto_cert_cache.cache_entry_size(); ++i) {
260 const CertVerificationCacheEntry& cache_entry =
261 proto_cert_cache.cache_entry(i);
262 if (!cache_entry.has_request_params() ||
263 !cache_entry.has_verification_time() ||
264 !cache_entry.has_cached_result()) {
265 detected_corrupted_data = true;
Ryan Sleevi 2016/06/09 22:38:41 DESIGN: Why do you continue deserializing once dat
ramant (doing other things) 2016/06/10 06:13:51 If an entry is corrupted, ignore that entry and co
266 continue;
267 }
268
269 const CertVerificationRequestParams& proto_request_params =
270 cache_entry.request_params();
271
272 if (!proto_request_params.has_certificate() ||
273 !proto_request_params.has_hostname() ||
274 proto_request_params.hostname().empty() ||
275 !proto_request_params.has_flags() ||
276 !proto_request_params.has_ocsp_response()) {
277 detected_corrupted_data = true;
278 continue;
279 }
280
281 scoped_refptr<X509Certificate> certificate = DeserializeCertificate(
282 proto_request_params.certificate(), deserialized_der_certs);
283 if (!certificate || !certificate.get()) {
Ryan Sleevi 2016/06/09 22:38:42 !certificate.get() is redundant with !certificate
ramant (doing other things) 2016/06/10 06:13:52 Done.
284 detected_corrupted_data = true;
285 continue;
286 }
287
288 std::string hostname(proto_request_params.hostname());
Ryan Sleevi 2016/06/09 22:38:41 Why make a copy like this? Or with line 290? Why n
ramant (doing other things) 2016/06/10 06:13:51 Done.
289 int flags = proto_request_params.flags();
290 std::string ocsp_response(proto_request_params.ocsp_response());
291 CertificateList additional_trust_anchors;
292 bool cert_error = false;
293 for (int i = 0; i < proto_request_params.additional_trust_anchors_size();
294 ++i) {
295 const CertVerificationCertificate& proto_certificate =
296 proto_request_params.additional_trust_anchors(i);
297 scoped_refptr<X509Certificate> cert =
298 DeserializeCertificate(proto_certificate, deserialized_der_certs);
299 if (!cert || !cert.get()) {
Ryan Sleevi 2016/06/09 22:38:41 See above about .get()
ramant (doing other things) 2016/06/10 06:13:52 Done.
300 cert_error = true;
301 break;
302 }
303 additional_trust_anchors.push_back(cert);
304 }
305 if (cert_error) {
306 detected_corrupted_data = true;
307 continue;
308 }
309
310 CertVerifier::RequestParams params(certificate, hostname, flags,
311 ocsp_response, additional_trust_anchors);
312
313 base::Time verification_time =
314 base::Time::FromInternalValue(cache_entry.verification_time());
315
316 const CertVerificationCachedResult& proto_cached_result =
317 cache_entry.cached_result();
318 CertVerifyResult result;
319 int error;
320 if (!DeserializeCachedResult(proto_cached_result, deserialized_der_certs,
321 &error, &result)) {
322 detected_corrupted_data = true;
323 continue;
324 }
325
326 if (!verifier->AddEntry(params, error, result, verification_time)) {
327 detected_corrupted_data = true;
Ryan Sleevi 2016/06/09 22:38:42 BUG: AddEntry failing does not mean data was corru
ramant (doing other things) 2016/06/10 06:13:52 Done.
328 continue;
329 }
330 }
331 UMA_HISTOGRAM_TIMES("Net.CertVerifierCachePersister.DeserializeTime",
332 base::TimeTicks::Now() - load_cache_start_time);
Ryan Sleevi 2016/06/09 22:38:41 Ditto
ramant (doing other things) 2016/06/10 06:13:51 Done.
333 return !detected_corrupted_data;
334 }
335
336 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698