OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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, |
estark
2016/01/18 17:04:43
I can add UMA metrics and/or netlog events in this
| |
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 CertStatus cert_status, | |
267 const ct::EVCertsWhitelist* ev_whitelist, | |
268 EVComplianceDetails* result) { | |
269 if ((cert_status & CERT_STATUS_CT_COMPLIANCE_FAILED) == 0) | |
270 result->status = EV_POLICY_STATUS_COMPLIANT; | |
Eran Messeri
2016/01/21 13:15:38
Nit: Set the result->status to something else so t
estark
2016/01/21 22:46:14
Done.
| |
271 if (!IsBuildTimely()) | |
272 return; | |
273 result->build_timely = true; | |
274 if (ev_whitelist && ev_whitelist->IsValid()) | |
275 result->whitelist_version = ev_whitelist->Version(); | |
276 | |
277 if (result->status != EV_POLICY_STATUS_COMPLIANT && | |
278 IsCertificateInWhitelist(*cert, ev_whitelist)) { | |
279 result->status = EV_POLICY_STATUS_IN_WHITELIST; | |
280 } | |
295 } | 281 } |
296 | 282 |
297 } // namespace | 283 } // namespace |
298 | 284 |
299 bool CTPolicyEnforcer::DoesConformToCTEVPolicy( | 285 bool CTPolicyEnforcer::DoesConformToCertPolicy( |
300 X509Certificate* cert, | 286 X509Certificate* cert, |
287 const ct::CTVerifyResult& ct_result) { | |
288 return CheckCertPolicyCompliance(cert, ct_result); | |
289 } | |
290 | |
291 bool CTPolicyEnforcer::DoesConformToEVPolicy( | |
292 X509Certificate* cert, | |
293 CertStatus cert_status, | |
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 DCHECK_NE((cert_status & CERT_STATUS_IS_EV), 0u); |
305 | 297 |
306 CheckCTEVPolicyCompliance(cert, ev_whitelist, ct_result, &details); | 298 EVComplianceDetails details; |
299 CheckEVPolicyCompliance(cert, cert_status, ev_whitelist, &details); | |
307 | 300 |
308 NetLog::ParametersCallback net_log_callback = | 301 NetLog::ParametersCallback net_log_callback = |
309 base::Bind(&NetLogComplianceCheckResultCallback, base::Unretained(cert), | 302 base::Bind(&NetLogComplianceCheckResultCallback, base::Unretained(cert), |
310 base::Unretained(&details)); | 303 base::Unretained(&details)); |
311 | 304 |
312 net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED, | 305 net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED, |
313 net_log_callback); | 306 net_log_callback); |
314 | 307 |
315 if (!details.ct_presence_required) | 308 LogEVPolicyStatusToUMA(details.status, ev_whitelist); |
316 return true; | |
317 | 309 |
318 if (!details.build_timely) | 310 if (details.status == EV_POLICY_STATUS_IN_WHITELIST) |
319 return false; | 311 return details.build_timely; |
Eran Messeri
2016/01/21 13:15:38
Seems like there's a logical change hiding in here
estark
2016/01/21 22:46:14
Hmm, I think I might have actually done this inten
| |
320 | 312 |
321 LogCTComplianceStatusToUMA(details.status, ev_whitelist); | 313 return (details.status == EV_POLICY_STATUS_COMPLIANT); |
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 |
OLD | NEW |