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

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

Issue 782333002: Certificate Transparency: Adding finch and NetLog logging for EV certs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix typo in log_view_painter, update params description in netlog Created 6 years 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/cert_policy_enforcer.h" 5 #include "net/cert/cert_policy_enforcer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h"
9 #include "base/build_time.h" 10 #include "base/build_time.h"
11 #include "base/callback_helpers.h"
10 #include "base/metrics/field_trial.h" 12 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
12 #include "base/numerics/safe_conversions.h" 14 #include "base/numerics/safe_conversions.h"
13 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
16 #include "base/values.h"
17 #include "net/base/net_log.h"
14 #include "net/cert/ct_ev_whitelist.h" 18 #include "net/cert/ct_ev_whitelist.h"
15 #include "net/cert/ct_verify_result.h" 19 #include "net/cert/ct_verify_result.h"
16 #include "net/cert/signed_certificate_timestamp.h" 20 #include "net/cert/signed_certificate_timestamp.h"
17 #include "net/cert/x509_certificate.h" 21 #include "net/cert/x509_certificate.h"
22 #include "net/cert/x509_certificate_net_log_param.h"
18 23
19 namespace net { 24 namespace net {
20 25
21 namespace { 26 namespace {
22 27
23 bool IsEmbeddedSCT(const scoped_refptr<ct::SignedCertificateTimestamp>& sct) { 28 bool IsEmbeddedSCT(const scoped_refptr<ct::SignedCertificateTimestamp>& sct) {
24 return sct->origin == ct::SignedCertificateTimestamp::SCT_EMBEDDED; 29 return sct->origin == ct::SignedCertificateTimestamp::SCT_EMBEDDED;
25 } 30 }
26 31
27 // Returns true if the current build is recent enough to ensure that 32 // Returns true if the current build is recent enough to ensure that
(...skipping 18 matching lines...) Expand all
46 uint32_t month_diff = (exploded_expiry.year - exploded_start.year) * 12 + 51 uint32_t month_diff = (exploded_expiry.year - exploded_start.year) * 12 +
47 (exploded_expiry.month - exploded_start.month); 52 (exploded_expiry.month - exploded_start.month);
48 53
49 // Add any remainder as a full month. 54 // Add any remainder as a full month.
50 if (exploded_expiry.day_of_month > exploded_start.day_of_month) 55 if (exploded_expiry.day_of_month > exploded_start.day_of_month)
51 ++month_diff; 56 ++month_diff;
52 57
53 return month_diff; 58 return month_diff;
54 } 59 }
55 60
61 bool HasRequiredNumberOfSCTs(X509Certificate* cert,
mmenke 2014/12/16 16:40:12 optional nit: This should probably be const X509C
Eran Messeri 2014/12/17 16:19:31 Done, here and in IsCertificateInWhitelist
62 const ct::CTVerifyResult& ct_result) {
63 // TODO(eranm): Count the number of *independent* SCTs once the information
64 // about log operators is available, crbug.com/425174
65 size_t num_valid_scts = ct_result.verified_scts.size();
66 size_t num_embedded_scts =
67 std::count_if(ct_result.verified_scts.begin(),
68 ct_result.verified_scts.end(), IsEmbeddedSCT);
69
70 size_t num_non_embedded_scts = num_valid_scts - num_embedded_scts;
71 // If at least two valid SCTs were delivered by means other than embedding
72 // (i.e. in a TLS extension or OCSP), then the certificate conforms to bullet
73 // number 3 of the "Qualifying Certificate" section of the CT/EV policy.
74 if (num_non_embedded_scts >= 2)
75 return true;
76
77 if (cert->valid_start().is_null() || cert->valid_expiry().is_null() ||
78 cert->valid_start().is_max() || cert->valid_expiry().is_max()) {
79 // Will not be able to calculate the certificate's validity period.
80 return false;
81 }
82
83 uint32_t expiry_in_months_approx =
84 ApproximateMonthDifference(cert->valid_start(), cert->valid_expiry());
85
86 // For embedded SCTs, if the certificate has the number of SCTs specified in
87 // table 1 of the "Qualifying Certificate" section of the CT/EV policy, then
88 // it qualifies.
89 size_t num_required_embedded_scts;
90 if (expiry_in_months_approx > 39) {
91 num_required_embedded_scts = 5;
92 } else if (expiry_in_months_approx > 27) {
93 num_required_embedded_scts = 4;
94 } else if (expiry_in_months_approx >= 15) {
95 num_required_embedded_scts = 3;
96 } else {
97 num_required_embedded_scts = 2;
98 }
99
100 return num_embedded_scts >= num_required_embedded_scts;
101 }
102
56 enum CTComplianceStatus { 103 enum CTComplianceStatus {
57 CT_NOT_COMPLIANT = 0, 104 CT_NOT_COMPLIANT = 0,
58 CT_IN_WHITELIST = 1, 105 CT_IN_WHITELIST = 1,
59 CT_ENOUGH_SCTS = 2, 106 CT_ENOUGH_SCTS = 2,
60 CT_COMPLIANCE_MAX, 107 CT_COMPLIANCE_MAX,
61 }; 108 };
62 109
110 const char* ComplianceStatusToString(CTComplianceStatus status) {
111 switch (status) {
112 case CT_NOT_COMPLIANT:
113 return "NOT_COMPLIANT";
114 break;
115 case CT_IN_WHITELIST:
116 return "WHITELISTED";
117 break;
118 case CT_ENOUGH_SCTS:
119 return "ENOUGH_SCTS";
120 break;
121 case CT_COMPLIANCE_MAX:
122 break;
123 }
124
125 return "unknown";
126 }
127
63 void LogCTComplianceStatusToUMA(CTComplianceStatus status) { 128 void LogCTComplianceStatusToUMA(CTComplianceStatus status) {
64 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVCertificateCTCompliance", status, 129 UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVCertificateCTCompliance", status,
65 CT_COMPLIANCE_MAX); 130 CT_COMPLIANCE_MAX);
66 } 131 }
67 132
68 } // namespace 133 struct ComplianceDetails {
134 ComplianceDetails()
135 : ct_presence_required(false),
136 build_timely(false),
137 status(CT_NOT_COMPLIANT) {}
69 138
70 CertPolicyEnforcer::CertPolicyEnforcer(bool require_ct_for_ev) 139 // Whether enforcement of the policy was required or not.
71 : require_ct_for_ev_(require_ct_for_ev) { 140 bool ct_presence_required;
141 // Whether the build is not older than 10 weeks. The value is meaningful only
142 // if |ct_presence_required| is true.
143 bool build_timely;
144 // Compliance status - meaningful only if |ct_presence_required| and
145 // |build_timely| are true.
146 CTComplianceStatus status;
147 // EV whitelist version.
148 base::Version whitelist_version;
149 };
150
151 base::Value* NetLogComplianceCheckResultCallback(X509Certificate* cert,
152 ComplianceDetails* details,
153 NetLog::LogLevel log_level) {
154 base::DictionaryValue* dict = new base::DictionaryValue();
155 dict->Set("certificate", NetLogX509CertificateCallback(cert, log_level));
156 dict->SetBoolean("policy_enforcement_required",
157 details->ct_presence_required);
158 if (details->ct_presence_required) {
159 dict->SetBoolean("build_timely", details->build_timely);
160 if (details->build_timely) {
161 dict->SetString("ct_compliance_status",
162 ComplianceStatusToString(details->status));
163 if (details->whitelist_version.IsValid())
164 dict->SetString("ev_whitelist_version",
165 details->whitelist_version.GetString());
166 }
167 }
168 return dict;
72 } 169 }
73 170
74 CertPolicyEnforcer::~CertPolicyEnforcer() { 171 bool IsCertificateInWhitelist(X509Certificate* cert,
75 } 172 const ct::EVCertsWhitelist* ev_whitelist) {
76
77 bool CertPolicyEnforcer::DoesConformToCTEVPolicy(
78 X509Certificate* cert,
79 const ct::EVCertsWhitelist* ev_whitelist,
80 const ct::CTVerifyResult& ct_result) {
81 if (!require_ct_for_ev_)
82 return true;
83
84 if (!IsBuildTimely())
85 return false;
86
87 if (IsCertificateInWhitelist(cert, ev_whitelist)) {
88 LogCTComplianceStatusToUMA(CT_IN_WHITELIST);
89 return true;
90 }
91
92 if (HasRequiredNumberOfSCTs(cert, ct_result)) {
93 LogCTComplianceStatusToUMA(CT_ENOUGH_SCTS);
94 return true;
95 }
96
97 LogCTComplianceStatusToUMA(CT_NOT_COMPLIANT);
98 return false;
99 }
100
101 bool CertPolicyEnforcer::IsCertificateInWhitelist(
102 X509Certificate* cert,
103 const ct::EVCertsWhitelist* ev_whitelist) {
104 bool cert_in_ev_whitelist = false; 173 bool cert_in_ev_whitelist = false;
105 if (ev_whitelist && ev_whitelist->IsValid()) { 174 if (ev_whitelist && ev_whitelist->IsValid()) {
106 const SHA256HashValue fingerprint( 175 const SHA256HashValue fingerprint(
107 X509Certificate::CalculateFingerprint256(cert->os_cert_handle())); 176 X509Certificate::CalculateFingerprint256(cert->os_cert_handle()));
108 177
109 std::string truncated_fp = 178 std::string truncated_fp =
110 std::string(reinterpret_cast<const char*>(fingerprint.data), 8); 179 std::string(reinterpret_cast<const char*>(fingerprint.data), 8);
111 cert_in_ev_whitelist = ev_whitelist->ContainsCertificateHash(truncated_fp); 180 cert_in_ev_whitelist = ev_whitelist->ContainsCertificateHash(truncated_fp);
112 181
113 UMA_HISTOGRAM_BOOLEAN("Net.SSL_EVCertificateInWhitelist", 182 UMA_HISTOGRAM_BOOLEAN("Net.SSL_EVCertificateInWhitelist",
114 cert_in_ev_whitelist); 183 cert_in_ev_whitelist);
115 } 184 }
116 return cert_in_ev_whitelist; 185 return cert_in_ev_whitelist;
117 } 186 }
118 187
119 bool CertPolicyEnforcer::HasRequiredNumberOfSCTs( 188 void CheckCTEVPolicyCompliance(X509Certificate* cert,
189 const ct::EVCertsWhitelist* ev_whitelist,
190 const ct::CTVerifyResult& ct_result,
191 ComplianceDetails* result) {
192 result->ct_presence_required = true;
193
194 if (!IsBuildTimely())
195 return;
196 result->build_timely = true;
197
198 if (ev_whitelist && ev_whitelist->IsValid())
199 result->whitelist_version = ev_whitelist->Version();
200
201 if (IsCertificateInWhitelist(cert, ev_whitelist)) {
202 result->status = CT_IN_WHITELIST;
203 return;
204 }
205
206 if (HasRequiredNumberOfSCTs(cert, ct_result)) {
207 result->status = CT_ENOUGH_SCTS;
208 return;
209 }
210
211 result->status = CT_NOT_COMPLIANT;
212 }
213
214 } // namespace
215
216 CertPolicyEnforcer::CertPolicyEnforcer(bool require_ct_for_ev)
217 : require_ct_for_ev_(require_ct_for_ev) {
218 }
219
220 CertPolicyEnforcer::~CertPolicyEnforcer() {
221 }
222
223 bool CertPolicyEnforcer::DoesConformToCTEVPolicy(
120 X509Certificate* cert, 224 X509Certificate* cert,
121 const ct::CTVerifyResult& ct_result) { 225 const ct::EVCertsWhitelist* ev_whitelist,
122 // TODO(eranm): Count the number of *independent* SCTs once the information 226 const ct::CTVerifyResult& ct_result,
123 // about log operators is available, crbug.com/425174 227 const BoundNetLog& net_log) {
124 size_t num_valid_scts = ct_result.verified_scts.size(); 228 ComplianceDetails details;
125 size_t num_embedded_scts =
126 std::count_if(ct_result.verified_scts.begin(),
127 ct_result.verified_scts.end(), IsEmbeddedSCT);
128 229
129 size_t num_non_embedded_scts = num_valid_scts - num_embedded_scts; 230 if (require_ct_for_ev_)
130 // If at least two valid SCTs were delivered by means other than embedding 231 CheckCTEVPolicyCompliance(cert, ev_whitelist, ct_result, &details);
131 // (i.e. in a TLS extension or OCSP), then the certificate conforms to bullet 232
132 // number 3 of the "Qualifying Certificate" section of the CT/EV policy. 233 NetLog::ParametersCallback net_log_callback =
133 if (num_non_embedded_scts >= 2) 234 base::Bind(&NetLogComplianceCheckResultCallback, base::Unretained(cert),
235 base::Unretained(&details));
236
237 net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED,
238 net_log_callback);
239
240 if (!details.ct_presence_required)
134 return true; 241 return true;
135 242
136 if (cert->valid_start().is_null() || cert->valid_expiry().is_null() || 243 if (!details.build_timely)
137 cert->valid_start().is_max() || cert->valid_expiry().is_max()) {
138 // Will not be able to calculate the certificate's validity period.
139 return false; 244 return false;
140 }
141 245
142 uint32_t expiry_in_months_approx = 246 LogCTComplianceStatusToUMA(details.status);
143 ApproximateMonthDifference(cert->valid_start(), cert->valid_expiry());
144 247
145 // For embedded SCTs, if the certificate has the number of SCTs specified in 248 if (details.status == CT_IN_WHITELIST || details.status == CT_ENOUGH_SCTS)
146 // table 1 of the "Qualifying Certificate" section of the CT/EV policy, then 249 return true;
147 // it qualifies.
148 size_t num_required_embedded_scts;
149 if (expiry_in_months_approx > 39) {
150 num_required_embedded_scts = 5;
151 } else if (expiry_in_months_approx > 27) {
152 num_required_embedded_scts = 4;
153 } else if (expiry_in_months_approx >= 15) {
154 num_required_embedded_scts = 3;
155 } else {
156 num_required_embedded_scts = 2;
157 }
158 250
159 return num_embedded_scts >= num_required_embedded_scts; 251 return false;
160 } 252 }
161 253
162 } // namespace net 254 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698