Delete unused build/android/ant/apk-compile.py
[chromium-blink-merge.git] / net / cert / multi_log_ct_verifier.cc
blob5094da026d03f38bf8cee4c54c7cea5ce2f32580
1 // Copyright 2013 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.
5 #include "net/cert/multi_log_ct_verifier.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/metrics/histogram.h"
10 #include "net/base/net_errors.h"
11 #include "net/base/net_log.h"
12 #include "net/cert/ct_log_verifier.h"
13 #include "net/cert/ct_objects_extractor.h"
14 #include "net/cert/ct_serialization.h"
15 #include "net/cert/ct_signed_certificate_timestamp_log_param.h"
16 #include "net/cert/ct_verify_result.h"
17 #include "net/cert/sct_status_flags.h"
18 #include "net/cert/x509_certificate.h"
20 namespace net {
22 namespace {
24 // Record SCT verification status. This metric would help detecting presence
25 // of unknown CT logs as well as bad deployments (invalid SCTs).
26 void LogSCTStatusToUMA(ct::SCTVerifyStatus status) {
27 UMA_HISTOGRAM_ENUMERATION(
28 "Net.CertificateTransparency.SCTStatus", status, ct::SCT_STATUS_MAX);
31 // Record SCT origin enum. This metric measure the popularity
32 // of the various channels of providing SCTs for a certificate.
33 void LogSCTOriginToUMA(ct::SignedCertificateTimestamp::Origin origin) {
34 UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.SCTOrigin",
35 origin,
36 ct::SignedCertificateTimestamp::SCT_ORIGIN_MAX);
39 // Count the number of SCTs that were available for each SSL connection
40 // (including SCTs embedded in the certificate).
41 // This metric would allow measuring:
42 // * Of all SSL connections, how many had SCTs available for validation.
43 // * When SCTs are available, how many are available per connection.
44 void LogNumSCTsToUMA(const ct::CTVerifyResult& result) {
45 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.CertificateTransparency.SCTsPerConnection",
46 result.invalid_scts.size() +
47 result.verified_scts.size() +
48 result.unknown_logs_scts.size(),
50 10,
51 11);
54 } // namespace
56 MultiLogCTVerifier::MultiLogCTVerifier() { }
58 MultiLogCTVerifier::~MultiLogCTVerifier() { }
60 void MultiLogCTVerifier::AddLog(scoped_ptr<CTLogVerifier> log_verifier) {
61 DCHECK(log_verifier);
62 if (!log_verifier)
63 return;
65 linked_ptr<CTLogVerifier> log(log_verifier.release());
66 logs_[log->key_id()] = log;
69 int MultiLogCTVerifier::Verify(
70 X509Certificate* cert,
71 const std::string& stapled_ocsp_response,
72 const std::string& sct_list_from_tls_extension,
73 ct::CTVerifyResult* result,
74 const BoundNetLog& net_log) {
75 DCHECK(cert);
76 DCHECK(result);
78 result->verified_scts.clear();
79 result->invalid_scts.clear();
80 result->unknown_logs_scts.clear();
82 bool has_verified_scts = false;
84 std::string embedded_scts;
85 if (!cert->GetIntermediateCertificates().empty() &&
86 ct::ExtractEmbeddedSCTList(
87 cert->os_cert_handle(),
88 &embedded_scts)) {
89 ct::LogEntry precert_entry;
91 has_verified_scts =
92 ct::GetPrecertLogEntry(
93 cert->os_cert_handle(),
94 cert->GetIntermediateCertificates().front(),
95 &precert_entry) &&
96 VerifySCTs(
97 embedded_scts,
98 precert_entry,
99 ct::SignedCertificateTimestamp::SCT_EMBEDDED,
100 result);
103 std::string sct_list_from_ocsp;
104 if (!stapled_ocsp_response.empty() &&
105 !cert->GetIntermediateCertificates().empty()) {
106 ct::ExtractSCTListFromOCSPResponse(
107 cert->GetIntermediateCertificates().front(), cert->serial_number(),
108 stapled_ocsp_response, &sct_list_from_ocsp);
111 // Log to Net Log, after extracting SCTs but before possibly failing on
112 // X.509 entry creation.
113 NetLog::ParametersCallback net_log_callback =
114 base::Bind(&NetLogRawSignedCertificateTimestampCallback,
115 &embedded_scts, &sct_list_from_ocsp, &sct_list_from_tls_extension);
117 net_log.AddEvent(
118 NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED,
119 net_log_callback);
121 ct::LogEntry x509_entry;
122 if (ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) {
123 has_verified_scts |= VerifySCTs(
124 sct_list_from_ocsp,
125 x509_entry,
126 ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
127 result);
129 has_verified_scts |= VerifySCTs(
130 sct_list_from_tls_extension,
131 x509_entry,
132 ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
133 result);
136 NetLog::ParametersCallback net_log_checked_callback =
137 base::Bind(&NetLogSignedCertificateTimestampCallback, result);
139 net_log.AddEvent(
140 NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED,
141 net_log_checked_callback);
143 LogNumSCTsToUMA(*result);
145 if (has_verified_scts)
146 return OK;
148 return ERR_CT_NO_SCTS_VERIFIED_OK;
151 bool MultiLogCTVerifier::VerifySCTs(
152 const std::string& encoded_sct_list,
153 const ct::LogEntry& expected_entry,
154 ct::SignedCertificateTimestamp::Origin origin,
155 ct::CTVerifyResult* result) {
156 if (logs_.empty())
157 return false;
159 base::StringPiece temp(encoded_sct_list);
160 std::vector<base::StringPiece> sct_list;
162 if (!ct::DecodeSCTList(&temp, &sct_list))
163 return false;
165 bool verified = false;
166 for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin();
167 it != sct_list.end(); ++it) {
168 base::StringPiece encoded_sct(*it);
169 LogSCTOriginToUMA(origin);
171 scoped_refptr<ct::SignedCertificateTimestamp> decoded_sct;
172 if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) {
173 LogSCTStatusToUMA(ct::SCT_STATUS_NONE);
174 // XXX(rsleevi): Should we really just skip over bad SCTs?
175 continue;
177 decoded_sct->origin = origin;
179 verified |= VerifySingleSCT(decoded_sct, expected_entry, result);
182 return verified;
185 bool MultiLogCTVerifier::VerifySingleSCT(
186 scoped_refptr<ct::SignedCertificateTimestamp> sct,
187 const ct::LogEntry& expected_entry,
188 ct::CTVerifyResult* result) {
190 // Assume this SCT is untrusted until proven otherwise.
191 IDToLogMap::iterator it = logs_.find(sct->log_id);
192 if (it == logs_.end()) {
193 DVLOG(1) << "SCT does not match any known log.";
194 result->unknown_logs_scts.push_back(sct);
195 LogSCTStatusToUMA(ct::SCT_STATUS_LOG_UNKNOWN);
196 return false;
199 sct->log_description = it->second->description();
201 if (!it->second->Verify(expected_entry, *sct)) {
202 DVLOG(1) << "Unable to verify SCT signature.";
203 result->invalid_scts.push_back(sct);
204 LogSCTStatusToUMA(ct::SCT_STATUS_INVALID);
205 return false;
208 // SCT verified ok, just make sure the timestamp is legitimate.
209 if (sct->timestamp > base::Time::Now()) {
210 DVLOG(1) << "SCT is from the future!";
211 result->invalid_scts.push_back(sct);
212 LogSCTStatusToUMA(ct::SCT_STATUS_INVALID);
213 return false;
216 LogSCTStatusToUMA(ct::SCT_STATUS_OK);
217 result->verified_scts.push_back(sct);
218 return true;
221 } // namespace net