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

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: rsleevi comments Created 4 years, 11 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
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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 // operated by Google and at least one log that is not operated by Google. This 127 // operated by Google and at least one log that is not operated by Google. This
128 // is required for SCTs after July 1st, 2015, as documented at 128 // is required for SCTs after July 1st, 2015, as documented at
129 // http://dev.chromium.org/Home/chromium-security/root-ca-policy/EVCTPlanMay2015 edition.pdf 129 // http://dev.chromium.org/Home/chromium-security/root-ca-policy/EVCTPlanMay2015 edition.pdf
130 bool HasEnoughDiverseSCTs(const ct::SCTList& verified_scts) { 130 bool HasEnoughDiverseSCTs(const ct::SCTList& verified_scts) {
131 size_t num_google_issued_scts = base::checked_cast<size_t>(std::count_if( 131 size_t num_google_issued_scts = base::checked_cast<size_t>(std::count_if(
132 verified_scts.begin(), verified_scts.end(), IsGoogleIssuedSCT)); 132 verified_scts.begin(), verified_scts.end(), IsGoogleIssuedSCT));
133 return (num_google_issued_scts > 0) && 133 return (num_google_issued_scts > 0) &&
134 (verified_scts.size() != num_google_issued_scts); 134 (verified_scts.size() != num_google_issued_scts);
135 } 135 }
136 136
137 enum CTComplianceStatus { 137 enum EVPolicyStatus {
138 CT_NOT_COMPLIANT = 0, 138 EV_POLICY_STATUS_NOT_COMPLIANT = 0,
139 CT_IN_WHITELIST = 1, 139 EV_POLICY_STATUS_IN_WHITELIST = 1,
140 CT_ENOUGH_SCTS = 2, 140 EV_POLICY_STATUS_COMPLIANT = 2,
141 CT_NOT_ENOUGH_DIVERSE_SCTS = 3, 141 EV_POLICY_STATUS_MAX,
142 CT_COMPLIANCE_MAX,
143 }; 142 };
144 143
145 const char* ComplianceStatusToString(CTComplianceStatus status) { 144 const char* EVPolicyStatusToString(EVPolicyStatus status) {
146 switch (status) { 145 switch (status) {
147 case CT_NOT_COMPLIANT: 146 case EV_POLICY_STATUS_NOT_COMPLIANT:
148 return "NOT_COMPLIANT"; 147 return "NOT_COMPLIANT";
149 break; 148 break;
150 case CT_IN_WHITELIST: 149 case EV_POLICY_STATUS_IN_WHITELIST:
151 return "WHITELISTED"; 150 return "WHITELISTED";
152 break; 151 break;
153 case CT_ENOUGH_SCTS: 152 case EV_POLICY_STATUS_COMPLIANT:
154 return "ENOUGH_SCTS"; 153 return "COMPLIANT";
155 break; 154 break;
156 case CT_NOT_ENOUGH_DIVERSE_SCTS: 155 case EV_POLICY_STATUS_MAX:
157 return "NOT_ENOUGH_DIVERSE_SCTS";
158 break;
159 case CT_COMPLIANCE_MAX:
160 break; 156 break;
161 } 157 }
162 158
163 return "unknown"; 159 return "unknown";
164 } 160 }
165 161
166 enum EVWhitelistStatus { 162 enum EVWhitelistStatus {
167 EV_WHITELIST_NOT_PRESENT = 0, 163 EV_WHITELIST_NOT_PRESENT = 0,
168 EV_WHITELIST_INVALID = 1, 164 EV_WHITELIST_INVALID = 1,
169 EV_WHITELIST_VALID = 2, 165 EV_WHITELIST_VALID = 2,
170 EV_WHITELIST_MAX, 166 EV_WHITELIST_MAX,
171 }; 167 };
172 168
173 void LogCTComplianceStatusToUMA(CTComplianceStatus status, 169 void LogEVPolicyStatusToUMA(EVPolicyStatus status,
174 const ct::EVCertsWhitelist* ev_whitelist) { 170 const ct::EVCertsWhitelist* ev_whitelist) {
175 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVCertificateCTCompliance", status, 171 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVCTPolicyStatus", status,
176 CT_COMPLIANCE_MAX); 172 EV_POLICY_STATUS_MAX);
177 if (status == CT_NOT_COMPLIANT) { 173 if (status == EV_POLICY_STATUS_NOT_COMPLIANT) {
178 EVWhitelistStatus ev_whitelist_status = EV_WHITELIST_NOT_PRESENT; 174 EVWhitelistStatus ev_whitelist_status = EV_WHITELIST_NOT_PRESENT;
179 if (ev_whitelist != NULL) { 175 if (ev_whitelist != NULL) {
180 if (ev_whitelist->IsValid()) 176 if (ev_whitelist->IsValid())
181 ev_whitelist_status = EV_WHITELIST_VALID; 177 ev_whitelist_status = EV_WHITELIST_VALID;
182 else 178 else
183 ev_whitelist_status = EV_WHITELIST_INVALID; 179 ev_whitelist_status = EV_WHITELIST_INVALID;
184 } 180 }
185 181
186 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVWhitelistValidityForNonCompliantCert", 182 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVWhitelistValidityForNonCompliantCert",
187 ev_whitelist_status, EV_WHITELIST_MAX); 183 ev_whitelist_status, EV_WHITELIST_MAX);
188 } 184 }
189 } 185 }
190 186
191 struct ComplianceDetails { 187 struct EVComplianceDetails {
192 ComplianceDetails() 188 EVComplianceDetails()
193 : ct_presence_required(false), 189 : build_timely(false), status(EV_POLICY_STATUS_NOT_COMPLIANT) {}
194 build_timely(false),
195 status(CT_NOT_COMPLIANT) {}
196 190
197 // Whether enforcement of the policy was required or not. 191 // True if the build is not older than 10 weeks.
198 bool ct_presence_required;
199 // Whether the build is not older than 10 weeks. The value is meaningful only
200 // if |ct_presence_required| is true.
201 bool build_timely; 192 bool build_timely;
202 // Compliance status - meaningful only if |ct_presence_required| and 193 // Compliance status. Cannot be EV_POLICY_STATUS_IS_WHITELISTED if
203 // |build_timely| are true. 194 // |build_timely| is false.
204 CTComplianceStatus status; 195 EVPolicyStatus status;
205 // EV whitelist version. 196 // EV whitelist version. Only set if |build_timely| is true.
206 base::Version whitelist_version; 197 base::Version whitelist_version;
207 }; 198 };
208 199
209 scoped_ptr<base::Value> NetLogComplianceCheckResultCallback( 200 scoped_ptr<base::Value> NetLogComplianceCheckResultCallback(
210 X509Certificate* cert, 201 X509Certificate* cert,
211 ComplianceDetails* details, 202 EVComplianceDetails* details,
212 NetLogCaptureMode capture_mode) { 203 NetLogCaptureMode capture_mode) {
213 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 204 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
214 dict->Set("certificate", NetLogX509CertificateCallback(cert, capture_mode)); 205 dict->Set("certificate", NetLogX509CertificateCallback(cert, capture_mode));
215 dict->SetBoolean("policy_enforcement_required", 206 dict->SetBoolean("policy_enforcement_required", true);
216 details->ct_presence_required); 207 dict->SetBoolean("build_timely", details->build_timely);
217 if (details->ct_presence_required) { 208 dict->SetString("ct_compliance_status",
218 dict->SetBoolean("build_timely", details->build_timely); 209 EVPolicyStatusToString(details->status));
219 if (details->build_timely) { 210 if (details->whitelist_version.IsValid()) {
220 dict->SetString("ct_compliance_status", 211 dict->SetString("ev_whitelist_version",
221 ComplianceStatusToString(details->status)); 212 details->whitelist_version.GetString());
222 if (details->whitelist_version.IsValid())
223 dict->SetString("ev_whitelist_version",
224 details->whitelist_version.GetString());
225 }
226 } 213 }
227 return std::move(dict); 214 return std::move(dict);
228 } 215 }
229 216
230 // Returns true if all SCTs in |verified_scts| were issued on, or after, the 217 // Returns true if all SCTs in |verified_scts| were issued on, or after, the
231 // date specified in kDiverseSCTRequirementStartDate 218 // date specified in kDiverseSCTRequirementStartDate
232 bool AllSCTsPastDistinctSCTRequirementEnforcementDate( 219 bool AllSCTsPastDistinctSCTRequirementEnforcementDate(
233 const ct::SCTList& verified_scts) { 220 const ct::SCTList& verified_scts) {
234 // The date when diverse SCTs requirement is effective from. 221 // The date when diverse SCTs requirement is effective from.
235 // 2015-07-01 00:00:00 UTC. 222 // 2015-07-01 00:00:00 UTC.
(...skipping 18 matching lines...) Expand all
254 std::string truncated_fp = 241 std::string truncated_fp =
255 std::string(reinterpret_cast<const char*>(fingerprint.data), 8); 242 std::string(reinterpret_cast<const char*>(fingerprint.data), 8);
256 cert_in_ev_whitelist = ev_whitelist->ContainsCertificateHash(truncated_fp); 243 cert_in_ev_whitelist = ev_whitelist->ContainsCertificateHash(truncated_fp);
257 244
258 UMA_HISTOGRAM_BOOLEAN("Net.SSL_EVCertificateInWhitelist", 245 UMA_HISTOGRAM_BOOLEAN("Net.SSL_EVCertificateInWhitelist",
259 cert_in_ev_whitelist); 246 cert_in_ev_whitelist);
260 } 247 }
261 return cert_in_ev_whitelist; 248 return cert_in_ev_whitelist;
262 } 249 }
263 250
264 void CheckCTEVPolicyCompliance(X509Certificate* cert, 251 bool CheckCertPolicyCompliance(X509Certificate* cert,
265 const ct::EVCertsWhitelist* ev_whitelist, 252 const ct::CTVerifyResult& ct_result) {
266 const ct::CTVerifyResult& ct_result, 253 if (!HasRequiredNumberOfSCTs(*cert, ct_result))
267 ComplianceDetails* result) { 254 return false;
268 result->ct_presence_required = true;
269
270 if (!IsBuildTimely())
271 return;
272 result->build_timely = true;
273
274 if (ev_whitelist && ev_whitelist->IsValid())
275 result->whitelist_version = ev_whitelist->Version();
276
277 if (IsCertificateInWhitelist(*cert, ev_whitelist)) {
278 result->status = CT_IN_WHITELIST;
279 return;
280 }
281
282 if (!HasRequiredNumberOfSCTs(*cert, ct_result)) {
283 result->status = CT_NOT_COMPLIANT;
284 return;
285 }
286 255
287 if (AllSCTsPastDistinctSCTRequirementEnforcementDate( 256 if (AllSCTsPastDistinctSCTRequirementEnforcementDate(
288 ct_result.verified_scts) && 257 ct_result.verified_scts) &&
289 !HasEnoughDiverseSCTs(ct_result.verified_scts)) { 258 !HasEnoughDiverseSCTs(ct_result.verified_scts)) {
290 result->status = CT_NOT_ENOUGH_DIVERSE_SCTS; 259 return false;
291 return;
292 } 260 }
293 261
294 result->status = CT_ENOUGH_SCTS; 262 return true;
263 }
264
265 void CheckEVPolicyCompliance(X509Certificate* cert,
266 const ct::CTVerifyResult& ct_result,
267 const ct::EVCertsWhitelist* ev_whitelist,
268 EVComplianceDetails* result) {
269 result->status = EV_POLICY_STATUS_NOT_COMPLIANT;
270 if (CheckCertPolicyCompliance(cert, ct_result))
271 result->status = EV_POLICY_STATUS_COMPLIANT;
272 if (ev_whitelist && ev_whitelist->IsValid())
273 result->whitelist_version = ev_whitelist->Version();
274
275 if (result->status != EV_POLICY_STATUS_COMPLIANT &&
276 IsCertificateInWhitelist(*cert, ev_whitelist)) {
277 result->status = EV_POLICY_STATUS_IN_WHITELIST;
278 }
295 } 279 }
296 280
297 } // namespace 281 } // namespace
298 282
299 bool CTPolicyEnforcer::DoesConformToCTEVPolicy( 283 bool CTPolicyEnforcer::DoesConformToCertPolicy(
300 X509Certificate* cert, 284 X509Certificate* cert,
285 const ct::CTVerifyResult& ct_result) {
286 if (!IsBuildTimely())
Ryan Sleevi 2016/01/23 02:08:10 Perhaps it's worth documenting why we check build
estark 2016/01/30 17:01:56 Done.
287 return false;
288 return CheckCertPolicyCompliance(cert, ct_result);
289 }
290
291 bool CTPolicyEnforcer::DoesConformToEVPolicy(
292 X509Certificate* cert,
293 const ct::CTVerifyResult& ct_result,
301 const ct::EVCertsWhitelist* ev_whitelist, 294 const ct::EVCertsWhitelist* ev_whitelist,
302 const ct::CTVerifyResult& ct_result,
303 const BoundNetLog& net_log) { 295 const BoundNetLog& net_log) {
304 ComplianceDetails details; 296 EVComplianceDetails details;
305 297 details.build_timely = IsBuildTimely();
306 CheckCTEVPolicyCompliance(cert, ev_whitelist, ct_result, &details); 298 if (details.build_timely)
299 CheckEVPolicyCompliance(cert, ct_result, ev_whitelist, &details);
300 else
301 details.status = EV_POLICY_STATUS_NOT_COMPLIANT;
307 302
308 NetLog::ParametersCallback net_log_callback = 303 NetLog::ParametersCallback net_log_callback =
309 base::Bind(&NetLogComplianceCheckResultCallback, base::Unretained(cert), 304 base::Bind(&NetLogComplianceCheckResultCallback, base::Unretained(cert),
310 base::Unretained(&details)); 305 base::Unretained(&details));
311 306
312 net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED, 307 net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED,
313 net_log_callback); 308 net_log_callback);
314 309
315 if (!details.ct_presence_required) 310 LogEVPolicyStatusToUMA(details.status, ev_whitelist);
316 return true;
317 311
318 if (!details.build_timely) 312 return (details.status == EV_POLICY_STATUS_IN_WHITELIST ||
319 return false; 313 details.status == EV_POLICY_STATUS_COMPLIANT);
320
321 LogCTComplianceStatusToUMA(details.status, ev_whitelist);
322
323 if (details.status == CT_IN_WHITELIST || details.status == CT_ENOUGH_SCTS)
324 return true;
325
326 return false;
327 } 314 }
328 315
329 } // namespace net 316 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698