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

Side by Side Diff: components/cronet/cert/cert_verifier_cache_serializer.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: Minor fix to comment 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 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 "components/cronet/cert/cert_verifier_cache_serializer.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/logging.h"
11 #include "base/strings/string_piece.h"
12 #include "base/time/time.h"
13 #include "components/cronet/cert/proto/cert_verification.pb.h"
14 #include "net/base/hash_value.h"
15 #include "net/cert/caching_cert_verifier.h"
16 #include "net/cert/cert_verify_result.h"
17 #include "net/cert/x509_certificate.h"
18
19 namespace cronet {
20
21 namespace {
22
23 typedef std::vector<std::string> CertVector;
24 typedef std::map<std::string, size_t> SerializedCertMap;
Ryan Sleevi 2016/06/22 22:32:20 Maybe some documentation here (about what the size
ramant (doing other things) 2016/06/22 23:25:22 Done.
25 typedef std::map<size_t, std::string> DeserializedCertMap;
26
27 // Determine if |cert_handle| was already serialized. If so, simply return a
28 // reference to that entry. Otherwise, add a new entry to the set of certs to
29 // be serialized (|serialized_certs|). Returns true if |cert_handle| is
30 // serialized correctly.
31 bool SerializeCertHandle(const net::X509Certificate::OSCertHandle& cert_handle,
32 SerializedCertMap* serialized_certs,
33 size_t* cert_number) {
34 std::string encoded;
35 if (!net::X509Certificate::GetDEREncoded(cert_handle, &encoded))
36 return false;
37 auto result =
38 serialized_certs->insert({encoded, serialized_certs->size() + 1});
39 *cert_number = result.first->second;
40 return true;
41 }
42
43 // Update |certificate| with certificate number and updates |serialized_certs|
44 // with DER-encoded representation of certificate if the certicate is not in
45 // |serialized_certs|. Returns true if data is serialized correctly.
46 bool SerializeCertificate(net::X509Certificate* cert,
47 SerializedCertMap* serialized_certs,
48 cronet_pb::CertVerificationCertificate* certificate) {
49 size_t cert_number = 0;
50 if (!SerializeCertHandle(cert->os_cert_handle(), serialized_certs,
51 &cert_number)) {
52 return false;
53 }
54 certificate->add_cert_numbers(cert_number);
55 const net::X509Certificate::X509Certificate::OSCertHandles&
56 intermediate_ca_certs = cert->GetIntermediateCertificates();
57 for (const auto& intermediate : intermediate_ca_certs) {
58 if (!SerializeCertHandle(intermediate, serialized_certs, &cert_number))
59 return false;
60 certificate->add_cert_numbers(cert_number);
61 }
62 return true;
63 }
64
65 // Deserializes |certificate| using the certificate database provided in
66 // |deserialized_certs|. Returns the parsed certificate on success, or nullptr
67 // if deserialization failed.
68 scoped_refptr<net::X509Certificate> DeserializeCertificate(
69 const cronet_pb::CertVerificationCertificate& certificate,
70 const DeserializedCertMap& deserialized_certs) {
71 if (0 == certificate.cert_numbers_size())
72 return nullptr;
73 std::vector<base::StringPiece> der_cert_pieces(
74 certificate.cert_numbers_size());
75 for (int i = 0; i < certificate.cert_numbers_size(); i++) {
76 size_t cert_number = certificate.cert_numbers(i);
77 DeserializedCertMap::const_iterator it =
78 deserialized_certs.find(cert_number);
79 if (it == deserialized_certs.end())
80 return nullptr;
81 der_cert_pieces[i] = base::StringPiece(it->second);
82 }
83 return net::X509Certificate::CreateFromDERCertChain(der_cert_pieces);
84 }
85
86 // Serializes |params| into |request_params|, updating |serialized_certs| with
87 // the set of raw certificates that will be needed to deserialize the
88 // certificate in |request_params| via DeserializeCertificate().
89 bool SerializeRequestParams(
90 const net::CertVerifier::RequestParams& params,
91 SerializedCertMap* serialized_certs,
92 cronet_pb::CertVerificationRequestParams* request_params) {
93 cronet_pb::CertVerificationCertificate* certificate =
94 request_params->mutable_certificate();
95 if (!SerializeCertificate(params.certificate().get(), serialized_certs,
96 certificate)) {
97 return false;
98 }
99 request_params->set_hostname(params.hostname());
100 request_params->set_flags(params.flags());
101 request_params->set_ocsp_response(params.ocsp_response());
102 for (const auto& cert : params.additional_trust_anchors()) {
103 certificate = request_params->add_additional_trust_anchors();
104 if (!SerializeCertificate(cert.get(), serialized_certs, certificate))
105 return false;
106 }
107 return true;
108 }
109
110 // Serializes |result| into |cached_result|, updating |serialized_certs| with
111 // the set of raw certificates that will be needed to deserialize the
112 // certificate in |cached_result| via DeserializeCertificate().
113 bool SerializeCachedResult(
114 const net::CertVerifyResult& result,
115 SerializedCertMap* serialized_certs,
116 cronet_pb::CertVerificationCachedResult* cached_result) {
117 cronet_pb::CertVerificationResult* cert_verification_result =
118 cached_result->mutable_result();
119 cronet_pb::CertVerificationCertificate* certificate =
120 cert_verification_result->mutable_verified_cert();
121 if (!SerializeCertificate(result.verified_cert.get(), serialized_certs,
122 certificate)) {
123 return false;
124 }
125 cert_verification_result->set_cert_status(result.cert_status);
126 cert_verification_result->set_has_md2(result.has_md2);
127 cert_verification_result->set_has_md4(result.has_md4);
128 cert_verification_result->set_has_md5(result.has_md5);
129 cert_verification_result->set_has_sha1(result.has_sha1);
130 cert_verification_result->set_has_sha1_leaf(result.has_sha1_leaf);
131 for (const auto& value : result.public_key_hashes)
132 cert_verification_result->add_public_key_hashes(value.ToString());
133 cert_verification_result->set_is_issued_by_known_root(
134 result.is_issued_by_known_root);
135 cert_verification_result->set_is_issued_by_additional_trust_anchor(
136 result.is_issued_by_additional_trust_anchor);
137 cert_verification_result->set_common_name_fallback_used(
138 result.common_name_fallback_used);
139 return true;
140 }
141
142 // Deserializes |cached_result| using the certificate database provided in
143 // |deserialized_certs|. Returns the parsed net::CertVerifyResult on success, or
144 // nullptr if deserialization failed.
145 bool DeserializeCachedResult(
146 const cronet_pb::CertVerificationCachedResult& cached_result,
147 const DeserializedCertMap& deserialized_certs,
148 int* error,
149 net::CertVerifyResult* result) {
150 if (!cached_result.has_error() || !cached_result.has_result())
151 return false;
152
153 const cronet_pb::CertVerificationResult& cert_verification_result =
154 cached_result.result();
155 if (!cert_verification_result.has_verified_cert() ||
156 !cert_verification_result.has_cert_status()) {
157 return false;
158 }
159
160 *error = cached_result.error();
161
162 result->verified_cert = DeserializeCertificate(
163 cert_verification_result.verified_cert(), deserialized_certs);
164 if (!result->verified_cert)
165 return false;
166
167 for (int i = 0; i < cert_verification_result.public_key_hashes_size(); ++i) {
168 const std::string& public_key_hash =
169 cert_verification_result.public_key_hashes(i);
170 net::HashValue hash;
171 if (!hash.FromString(public_key_hash))
172 return false;
173 result->public_key_hashes.push_back(hash);
174 }
175 result->cert_status = cert_verification_result.cert_status();
176 result->has_md2 = cert_verification_result.has_md2();
177 result->has_md4 = cert_verification_result.has_md4();
178 result->has_md5 = cert_verification_result.has_md5();
179 result->has_sha1 = cert_verification_result.has_sha1();
180 result->has_sha1_leaf = cert_verification_result.has_sha1_leaf();
181 result->is_issued_by_known_root =
182 cert_verification_result.is_issued_by_known_root();
183 result->is_issued_by_additional_trust_anchor =
184 cert_verification_result.is_issued_by_additional_trust_anchor();
185 result->common_name_fallback_used =
186 cert_verification_result.common_name_fallback_used();
187 return true;
188 }
189
190 // Serializes |params|, |error|, |verify_result| and |verification_time| into
191 // |cert_cache|, updating |serialized_certs| with the set of raw certificates
192 // that will be needed to deserialize the certificate in |cert_cache| via
193 // DeserializeCertificate().
194 bool SerializeCachedEntry(const net::CachingCertVerifier::RequestParams& params,
195 int error,
196 const net::CertVerifyResult& verify_result,
197 base::Time verification_time,
198 cronet_pb::CertVerificationCache* cert_cache,
199 SerializedCertMap* serialized_certs) {
200 cronet_pb::CertVerificationCacheEntry* cache_entry =
201 cert_cache->add_cache_entry();
202
203 cronet_pb::CertVerificationRequestParams* request_params =
204 cache_entry->mutable_request_params();
205 if (!SerializeRequestParams(params, serialized_certs, request_params))
206 return false;
207
208 cronet_pb::CertVerificationCachedResult* cached_result =
209 cache_entry->mutable_cached_result();
210 if (!SerializeCachedResult(verify_result, serialized_certs, cached_result))
211 return false;
212 cached_result->set_error(error);
213
214 cache_entry->set_verification_time(verification_time.ToInternalValue());
215 return true;
216 }
217
218 class CacheVisitor : public net::CachingCertVerifier::CacheVisitor {
219 public:
220 CacheVisitor() : failed_to_serialize_(false) {}
221 ~CacheVisitor() override {}
222
223 bool VisitEntry(const net::CachingCertVerifier::RequestParams& params,
224 int error,
225 const net::CertVerifyResult& verify_result,
226 base::Time verification_time,
227 base::Time expiration_time) override {
228 if (!SerializeCachedEntry(params, error, verify_result, verification_time,
229 &cert_cache_, &serialized_certs_)) {
230 Reset();
231 return false;
232 }
233 return true;
234 }
235
236 void Reset() {
237 cert_cache_ = cronet_pb::CertVerificationCache();
238 failed_to_serialize_ = true;
239 }
240
241 void SerializeCerts() {
242 for (const auto& cert : serialized_certs_) {
243 cronet_pb::CertVerificationCertificateData* cert_entry =
244 cert_cache_.add_cert_entry();
245 cert_entry->set_cert(cert.first);
246 cert_entry->set_cert_number(cert.second);
247 }
248 }
249
250 const cronet_pb::CertVerificationCache& cert_cache() const {
251 return cert_cache_;
252 }
253
254 bool failed_to_serialize() const { return failed_to_serialize_; }
255
256 cronet_pb::CertVerificationCache cert_cache_;
257 SerializedCertMap serialized_certs_;
258 bool failed_to_serialize_;
259 };
260
261 struct CertVerifierCacheEntry {
262 CertVerifierCacheEntry(const net::CertVerifier::RequestParams& params,
263 int error,
264 const net::CertVerifyResult& result,
265 base::Time verification_time)
266 : params(params),
267 error(error),
268 result(result),
269 verification_time(verification_time) {}
270
271 net::CertVerifier::RequestParams params;
272 int error;
273 net::CertVerifyResult result;
274 base::Time verification_time;
275 };
276
277 } // namespace
278
279 cronet_pb::CertVerificationCache SerializeCertVerifierCache(
280 const net::CachingCertVerifier& verifier) {
281 CacheVisitor visitor;
282 verifier.VisitEntries(&visitor);
283
284 if (!visitor.failed_to_serialize())
285 visitor.SerializeCerts();
286 return visitor.cert_cache();
287 }
288
289 bool DeserializeCertVerifierCache(
290 const cronet_pb::CertVerificationCache& cert_cache,
291 net::CachingCertVerifier* verifier) {
292 DeserializedCertMap deserialized_certs;
293
294 if (cert_cache.cert_entry_size() == 0u ||
295 cert_cache.cache_entry_size() == 0u) {
296 return false;
297 }
298
299 // Build |deserialized_certs|'s certificate map.
300 for (int i = 0; i < cert_cache.cert_entry_size(); ++i) {
301 const cronet_pb::CertVerificationCertificateData& cert_entry =
302 cert_cache.cert_entry(i);
303 if (!cert_entry.has_cert() || !cert_entry.has_cert_number())
304 return false;
305 deserialized_certs.insert({cert_entry.cert_number(), cert_entry.cert()});
306 }
307
308 std::vector<std::unique_ptr<CertVerifierCacheEntry>>
309 cert_verifier_cache_entries;
310 for (int i = 0; i < cert_cache.cache_entry_size(); ++i) {
311 const cronet_pb::CertVerificationCacheEntry& cache_entry =
312 cert_cache.cache_entry(i);
313
314 // Verify |cache_entry|'s data.
315 if (!cache_entry.has_request_params() ||
316 !cache_entry.has_verification_time() ||
317 !cache_entry.has_cached_result()) {
318 return false;
319 }
320
321 const cronet_pb::CertVerificationRequestParams& request_params =
322 cache_entry.request_params();
323
324 // Verify |request_params|'s data.
325 if (!request_params.has_certificate() || !request_params.has_hostname() ||
326 request_params.hostname().empty() || !request_params.has_flags() ||
327 !request_params.has_ocsp_response()) {
328 return false;
329 }
330
331 // Deserialize |request_params|'s certificate using the certificate database
332 // provided in |deserialized_certs|.
333 scoped_refptr<net::X509Certificate> certificate = DeserializeCertificate(
334 request_params.certificate(), deserialized_certs);
335 if (!certificate)
336 return false;
337
338 // Deserialize |request_params|'s trust anchor certificates using the
339 // certificate database provided in |deserialized_certs|.
340 net::CertificateList additional_trust_anchors;
341 for (int i = 0; i < request_params.additional_trust_anchors_size(); ++i) {
342 const cronet_pb::CertVerificationCertificate& certificate =
343 request_params.additional_trust_anchors(i);
344 scoped_refptr<net::X509Certificate> cert =
345 DeserializeCertificate(certificate, deserialized_certs);
346 if (!cert)
347 return false;
348 additional_trust_anchors.push_back(cert);
349 }
350
351 net::CertVerifier::RequestParams params(
352 certificate, request_params.hostname(), request_params.flags(),
353 request_params.ocsp_response(), additional_trust_anchors);
354
355 // Deserialize |cached_result| into |result|.
356 const cronet_pb::CertVerificationCachedResult& cached_result =
357 cache_entry.cached_result();
358 net::CertVerifyResult result;
359 int error;
360 if (!DeserializeCachedResult(cached_result, deserialized_certs, &error,
361 &result)) {
362 return false;
363 }
364
365 base::Time verification_time =
366 base::Time::FromInternalValue(cache_entry.verification_time());
367 // We are deserializing the data that was persisted in the past and thus
368 // |verification_time| can not be in the future.
369 if (verification_time.is_null() || verification_time >= base::Time::Now())
370 return false;
371
372 std::unique_ptr<CertVerifierCacheEntry> cert_verifier_cache_entry(
373 new CertVerifierCacheEntry(params, error, result, verification_time));
374 cert_verifier_cache_entries.push_back(std::move(cert_verifier_cache_entry));
375 }
376
377 for (const auto& entry : cert_verifier_cache_entries) {
378 verifier->AddEntry(entry->params, entry->error, entry->result,
379 entry->verification_time);
380 }
381 return true;
382 }
383
384 } // namespace cronet
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698