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

Side by Side Diff: net/cert/ct_policy_enforcer.cc

Issue 1578993003: Add Expect CT policy that gets checked on all certs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 10 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/cert/ct_policy_enforcer.h ('k') | net/cert/ct_policy_enforcer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/cert/ct_policy_enforcer.h" 5 #include "net/cert/ct_policy_enforcer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 // operated by Google and at least one log that is not operated by Google. This 123 // operated by Google and at least one log that is not operated by Google. This
124 // is required for SCTs after July 1st, 2015, as documented at 124 // is required for SCTs after July 1st, 2015, as documented at
125 // http://dev.chromium.org/Home/chromium-security/root-ca-policy/EVCTPlanMay2015 edition.pdf 125 // http://dev.chromium.org/Home/chromium-security/root-ca-policy/EVCTPlanMay2015 edition.pdf
126 bool HasEnoughDiverseSCTs(const ct::SCTList& verified_scts) { 126 bool HasEnoughDiverseSCTs(const ct::SCTList& verified_scts) {
127 size_t num_google_issued_scts = base::checked_cast<size_t>(std::count_if( 127 size_t num_google_issued_scts = base::checked_cast<size_t>(std::count_if(
128 verified_scts.begin(), verified_scts.end(), IsGoogleIssuedSCT)); 128 verified_scts.begin(), verified_scts.end(), IsGoogleIssuedSCT));
129 return (num_google_issued_scts > 0) && 129 return (num_google_issued_scts > 0) &&
130 (verified_scts.size() != num_google_issued_scts); 130 (verified_scts.size() != num_google_issued_scts);
131 } 131 }
132 132
133 enum CTComplianceStatus { 133 const char* EVPolicyComplianceToString(ct::EVPolicyCompliance status) {
134 CT_NOT_COMPLIANT = 0, 134 switch (status) {
135 CT_IN_WHITELIST = 1, 135 case ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY:
136 CT_ENOUGH_SCTS = 2, 136 return "POLICY_DOES_NOT_APPLY";
137 CT_NOT_ENOUGH_DIVERSE_SCTS = 3, 137 case ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST:
138 CT_COMPLIANCE_MAX, 138 return "WHITELISTED";
139 }; 139 case ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS:
140 return "COMPLIES_VIA_SCTS";
141 case ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS:
142 return "NOT_ENOUGH_SCTS";
143 case ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS:
144 return "SCTS_NOT_DIVERSE";
145 case ct::EVPolicyCompliance::EV_POLICY_BUILD_NOT_TIMELY:
146 return "BUILD_NOT_TIMELY";
147 case ct::EVPolicyCompliance::EV_POLICY_MAX:
148 break;
149 }
140 150
141 const char* ComplianceStatusToString(CTComplianceStatus status) { 151 return "unknown";
152 }
153
154 const char* CertPolicyComplianceToString(ct::CertPolicyCompliance status) {
142 switch (status) { 155 switch (status) {
143 case CT_NOT_COMPLIANT: 156 case ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS:
144 return "NOT_COMPLIANT"; 157 return "COMPLIES_VIA_SCTS";
145 break; 158 case ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS:
146 case CT_IN_WHITELIST: 159 return "NOT_ENOUGH_SCTS";
147 return "WHITELISTED"; 160 case ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS:
148 break; 161 return "NOT_DIVERSE_SCTS";
149 case CT_ENOUGH_SCTS: 162 case ct::CertPolicyCompliance::CERT_POLICY_BUILD_NOT_TIMELY:
150 return "ENOUGH_SCTS"; 163 return "BUILD_NOT_TIMELY";
151 break;
152 case CT_NOT_ENOUGH_DIVERSE_SCTS:
153 return "NOT_ENOUGH_DIVERSE_SCTS";
154 break;
155 case CT_COMPLIANCE_MAX:
156 break;
157 } 164 }
158 165
159 return "unknown"; 166 return "unknown";
160 } 167 }
161 168
162 enum EVWhitelistStatus { 169 enum EVWhitelistStatus {
163 EV_WHITELIST_NOT_PRESENT = 0, 170 EV_WHITELIST_NOT_PRESENT = 0,
164 EV_WHITELIST_INVALID = 1, 171 EV_WHITELIST_INVALID = 1,
165 EV_WHITELIST_VALID = 2, 172 EV_WHITELIST_VALID = 2,
166 EV_WHITELIST_MAX, 173 EV_WHITELIST_MAX,
167 }; 174 };
168 175
169 void LogCTEVComplianceStatusToUMA(CTComplianceStatus status, 176 void LogEVPolicyComplianceToUMA(ct::EVPolicyCompliance status,
170 const ct::EVCertsWhitelist* ev_whitelist) { 177 const ct::EVCertsWhitelist* ev_whitelist) {
171 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVCertificateCTCompliance", status, 178 UMA_HISTOGRAM_ENUMERATION(
172 CT_COMPLIANCE_MAX); 179 "Net.SSL_EVCTCompliance", static_cast<int>(status),
173 if (status == CT_NOT_COMPLIANT) { 180 static_cast<int>(ct::EVPolicyCompliance::EV_POLICY_MAX));
181 if (status == ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS ||
182 status == ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS) {
174 EVWhitelistStatus ev_whitelist_status = EV_WHITELIST_NOT_PRESENT; 183 EVWhitelistStatus ev_whitelist_status = EV_WHITELIST_NOT_PRESENT;
175 if (ev_whitelist != NULL) { 184 if (ev_whitelist != NULL) {
176 if (ev_whitelist->IsValid()) 185 if (ev_whitelist->IsValid())
177 ev_whitelist_status = EV_WHITELIST_VALID; 186 ev_whitelist_status = EV_WHITELIST_VALID;
178 else 187 else
179 ev_whitelist_status = EV_WHITELIST_INVALID; 188 ev_whitelist_status = EV_WHITELIST_INVALID;
180 } 189 }
181 190
182 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVWhitelistValidityForNonCompliantCert", 191 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVWhitelistValidityForNonCompliantCert",
183 ev_whitelist_status, EV_WHITELIST_MAX); 192 ev_whitelist_status, EV_WHITELIST_MAX);
184 } 193 }
185 } 194 }
186 195
187 struct ComplianceDetails { 196 struct EVComplianceDetails {
188 ComplianceDetails() : build_timely(false), status(CT_NOT_COMPLIANT) {} 197 EVComplianceDetails()
198 : build_timely(false),
199 status(ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY) {}
189 200
190 // Whether the build is not older than 10 weeks. 201 // Whether the build is not older than 10 weeks.
191 bool build_timely; 202 bool build_timely;
192 // Compliance status - meaningful only if |build_timely| is true. 203 // Compliance status - meaningful only if |build_timely| is true.
193 CTComplianceStatus status; 204 ct::EVPolicyCompliance status;
194 // EV whitelist version. 205 // EV whitelist version.
195 base::Version whitelist_version; 206 base::Version whitelist_version;
196 }; 207 };
197 208
198 scoped_ptr<base::Value> NetLogComplianceCheckResultCallback( 209 scoped_ptr<base::Value> NetLogEVComplianceCheckResultCallback(
199 X509Certificate* cert, 210 X509Certificate* cert,
200 ComplianceDetails* details, 211 EVComplianceDetails* details,
201 NetLogCaptureMode capture_mode) { 212 NetLogCaptureMode capture_mode) {
202 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 213 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
203 dict->Set("certificate", NetLogX509CertificateCallback(cert, capture_mode)); 214 dict->Set("certificate", NetLogX509CertificateCallback(cert, capture_mode));
204 dict->SetBoolean("policy_enforcement_required", true); 215 dict->SetBoolean("policy_enforcement_required", true);
205 dict->SetBoolean("build_timely", details->build_timely); 216 dict->SetBoolean("build_timely", details->build_timely);
206 if (details->build_timely) { 217 if (details->build_timely) {
207 dict->SetString("ct_compliance_status", 218 dict->SetString("ct_compliance_status",
208 ComplianceStatusToString(details->status)); 219 EVPolicyComplianceToString(details->status));
209 if (details->whitelist_version.IsValid()) 220 if (details->whitelist_version.IsValid())
210 dict->SetString("ev_whitelist_version", 221 dict->SetString("ev_whitelist_version",
211 details->whitelist_version.GetString()); 222 details->whitelist_version.GetString());
212 } 223 }
213 return std::move(dict); 224 return std::move(dict);
214 } 225 }
215 226
227 scoped_ptr<base::Value> NetLogCertComplianceCheckResultCallback(
228 X509Certificate* cert,
229 bool build_timely,
230 ct::CertPolicyCompliance compliance,
231 NetLogCaptureMode capture_mode) {
232 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
233 dict->Set("certificate", NetLogX509CertificateCallback(cert, capture_mode));
234 dict->SetBoolean("build_timely", build_timely);
235 dict->SetString("ct_compliance_status",
236 CertPolicyComplianceToString(compliance));
237 return std::move(dict);
238 }
239
216 // Returns true if all SCTs in |verified_scts| were issued on, or after, the 240 // Returns true if all SCTs in |verified_scts| were issued on, or after, the
217 // date specified in kDiverseSCTRequirementStartDate 241 // date specified in kDiverseSCTRequirementStartDate
218 bool AllSCTsPastDistinctSCTRequirementEnforcementDate( 242 bool AllSCTsPastDistinctSCTRequirementEnforcementDate(
219 const ct::SCTList& verified_scts) { 243 const ct::SCTList& verified_scts) {
220 // The date when diverse SCTs requirement is effective from. 244 // The date when diverse SCTs requirement is effective from.
221 // 2015-07-01 00:00:00 UTC. 245 // 2015-07-01 00:00:00 UTC.
222 base::Time kDiverseSCTRequirementStartDate = 246 base::Time kDiverseSCTRequirementStartDate =
223 base::Time::FromInternalValue(13080182400000000); 247 base::Time::FromInternalValue(13080182400000000);
224 248
225 for (const auto& it : verified_scts) { 249 for (const auto& it : verified_scts) {
(...skipping 14 matching lines...) Expand all
240 std::string truncated_fp = 264 std::string truncated_fp =
241 std::string(reinterpret_cast<const char*>(fingerprint.data), 8); 265 std::string(reinterpret_cast<const char*>(fingerprint.data), 8);
242 cert_in_ev_whitelist = ev_whitelist->ContainsCertificateHash(truncated_fp); 266 cert_in_ev_whitelist = ev_whitelist->ContainsCertificateHash(truncated_fp);
243 267
244 UMA_HISTOGRAM_BOOLEAN("Net.SSL_EVCertificateInWhitelist", 268 UMA_HISTOGRAM_BOOLEAN("Net.SSL_EVCertificateInWhitelist",
245 cert_in_ev_whitelist); 269 cert_in_ev_whitelist);
246 } 270 }
247 return cert_in_ev_whitelist; 271 return cert_in_ev_whitelist;
248 } 272 }
249 273
274 ct::CertPolicyCompliance CheckCertPolicyCompliance(
275 X509Certificate* cert,
276 const ct::SCTList& verified_scts,
277 const BoundNetLog& net_log) {
278 if (!HasRequiredNumberOfSCTs(*cert, verified_scts))
279 return ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS;
280 if (AllSCTsPastDistinctSCTRequirementEnforcementDate(verified_scts) &&
281 !HasEnoughDiverseSCTs(verified_scts)) {
282 return ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS;
283 }
284
285 return ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS;
286 }
287
288 ct::EVPolicyCompliance CertPolicyComplianceToEVPolicyCompliance(
289 ct::CertPolicyCompliance cert_policy_compliance) {
290 switch (cert_policy_compliance) {
291 case ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS:
292 return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS;
293 case ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS:
294 return ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS;
295 case ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS:
296 return ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS;
297 case ct::CertPolicyCompliance::CERT_POLICY_BUILD_NOT_TIMELY:
298 return ct::EVPolicyCompliance::EV_POLICY_BUILD_NOT_TIMELY;
299 }
300 return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
301 }
302
250 void CheckCTEVPolicyCompliance(X509Certificate* cert, 303 void CheckCTEVPolicyCompliance(X509Certificate* cert,
251 const ct::EVCertsWhitelist* ev_whitelist, 304 const ct::EVCertsWhitelist* ev_whitelist,
252 const ct::SCTList& verified_scts, 305 const ct::SCTList& verified_scts,
253 ComplianceDetails* result) { 306 const BoundNetLog& net_log,
254 if (!IsBuildTimely()) 307 EVComplianceDetails* result) {
255 return; 308 result->status = CertPolicyComplianceToEVPolicyCompliance(
256 result->build_timely = true; 309 CheckCertPolicyCompliance(cert, verified_scts, net_log));
257
258 if (ev_whitelist && ev_whitelist->IsValid()) 310 if (ev_whitelist && ev_whitelist->IsValid())
259 result->whitelist_version = ev_whitelist->Version(); 311 result->whitelist_version = ev_whitelist->Version();
260 312
261 if (IsCertificateInWhitelist(*cert, ev_whitelist)) { 313 if (result->status != ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS &&
262 result->status = CT_IN_WHITELIST; 314 IsCertificateInWhitelist(*cert, ev_whitelist)) {
263 return; 315 result->status = ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST;
264 } 316 }
265
266 if (!HasRequiredNumberOfSCTs(*cert, verified_scts)) {
267 result->status = CT_NOT_COMPLIANT;
268 return;
269 }
270
271 if (AllSCTsPastDistinctSCTRequirementEnforcementDate(verified_scts) &&
272 !HasEnoughDiverseSCTs(verified_scts)) {
273 result->status = CT_NOT_ENOUGH_DIVERSE_SCTS;
274 return;
275 }
276
277 result->status = CT_ENOUGH_SCTS;
278 } 317 }
279 318
280 } // namespace 319 } // namespace
281 320
321 ct::CertPolicyCompliance CTPolicyEnforcer::DoesConformToCertPolicy(
322 X509Certificate* cert,
323 const ct::SCTList& verified_scts,
324 const BoundNetLog& net_log) {
325 // If the build is not timely, no certificate is considered compliant
326 // with CT policy. The reasoning is that, for example, a log might
327 // have been pulled and is no longer considered valid; thus, a client
328 // needs up-to-date information about logs to consider certificates to
329 // be compliant with policy.
330 bool build_timely = IsBuildTimely();
331 ct::CertPolicyCompliance compliance;
332 if (!build_timely) {
333 compliance = ct::CertPolicyCompliance::CERT_POLICY_BUILD_NOT_TIMELY;
334 } else {
335 compliance = CheckCertPolicyCompliance(cert, verified_scts, net_log);
336 }
337
338 NetLog::ParametersCallback net_log_callback =
339 base::Bind(&NetLogCertComplianceCheckResultCallback,
340 base::Unretained(cert), build_timely, compliance);
341
342 net_log.AddEvent(NetLog::TYPE_CERT_CT_COMPLIANCE_CHECKED, net_log_callback);
343
344 return compliance;
345 }
346
282 ct::EVPolicyCompliance CTPolicyEnforcer::DoesConformToCTEVPolicy( 347 ct::EVPolicyCompliance CTPolicyEnforcer::DoesConformToCTEVPolicy(
283 X509Certificate* cert, 348 X509Certificate* cert,
284 const ct::EVCertsWhitelist* ev_whitelist, 349 const ct::EVCertsWhitelist* ev_whitelist,
285 const ct::SCTList& verified_scts, 350 const ct::SCTList& verified_scts,
286 const BoundNetLog& net_log) { 351 const BoundNetLog& net_log) {
287 ComplianceDetails details; 352 EVComplianceDetails details;
288 353 // If the build is not timely, no certificate is considered compliant
289 CheckCTEVPolicyCompliance(cert, ev_whitelist, verified_scts, &details); 354 // with EV policy. The reasoning is that, for example, a log might
355 // have been pulled and is no longer considered valid; thus, a client
356 // needs up-to-date information about logs to consider certificates to
357 // be compliant with policy.
358 details.build_timely = IsBuildTimely();
359 if (!details.build_timely) {
360 details.status = ct::EVPolicyCompliance::EV_POLICY_BUILD_NOT_TIMELY;
361 } else {
362 CheckCTEVPolicyCompliance(cert, ev_whitelist, verified_scts, net_log,
363 &details);
364 }
290 365
291 NetLog::ParametersCallback net_log_callback = 366 NetLog::ParametersCallback net_log_callback =
292 base::Bind(&NetLogComplianceCheckResultCallback, base::Unretained(cert), 367 base::Bind(&NetLogEVComplianceCheckResultCallback, base::Unretained(cert),
293 base::Unretained(&details)); 368 base::Unretained(&details));
294 369
295 net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED, 370 net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED,
296 net_log_callback); 371 net_log_callback);
297 372
298 if (!details.build_timely) 373 if (!details.build_timely)
299 return ct::EVPolicyCompliance::EV_POLICY_BUILD_NOT_TIMELY; 374 return ct::EVPolicyCompliance::EV_POLICY_BUILD_NOT_TIMELY;
300 375
301 LogCTEVComplianceStatusToUMA(details.status, ev_whitelist); 376 LogEVPolicyComplianceToUMA(details.status, ev_whitelist);
302 377
303 switch (details.status) { 378 return details.status;
304 case CT_NOT_COMPLIANT:
305 return ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS;
306 case CT_IN_WHITELIST:
307 return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST;
308 case CT_ENOUGH_SCTS:
309 return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS;
310 case CT_NOT_ENOUGH_DIVERSE_SCTS:
311 return ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS;
312 case CT_COMPLIANCE_MAX:
313 return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
314 }
315
316 return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
317 } 379 }
318 380
319 } // namespace net 381 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/ct_policy_enforcer.h ('k') | net/cert/ct_policy_enforcer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698