• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/cert/multi_log_ct_verifier.h"
6 
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "net/base/net_errors.h"
10 #include "net/base/net_log.h"
11 #include "net/cert/ct_log_verifier.h"
12 #include "net/cert/ct_objects_extractor.h"
13 #include "net/cert/ct_serialization.h"
14 #include "net/cert/ct_signed_certificate_timestamp_log_param.h"
15 #include "net/cert/ct_verify_result.h"
16 #include "net/cert/x509_certificate.h"
17 
18 namespace net {
19 
MultiLogCTVerifier()20 MultiLogCTVerifier::MultiLogCTVerifier() { }
21 
~MultiLogCTVerifier()22 MultiLogCTVerifier::~MultiLogCTVerifier() { }
23 
AddLog(scoped_ptr<CTLogVerifier> log_verifier)24 void MultiLogCTVerifier::AddLog(scoped_ptr<CTLogVerifier> log_verifier) {
25   DCHECK(log_verifier);
26   if (!log_verifier)
27     return;
28 
29   linked_ptr<CTLogVerifier> log(log_verifier.release());
30   logs_[log->key_id()] = log;
31 }
32 
Verify(X509Certificate * cert,const std::string & stapled_ocsp_response,const std::string & sct_list_from_tls_extension,ct::CTVerifyResult * result,const BoundNetLog & net_log)33 int MultiLogCTVerifier::Verify(
34     X509Certificate* cert,
35     const std::string& stapled_ocsp_response,
36     const std::string& sct_list_from_tls_extension,
37     ct::CTVerifyResult* result,
38     const BoundNetLog& net_log)  {
39   DCHECK(cert);
40   DCHECK(result);
41 
42   result->verified_scts.clear();
43   result->invalid_scts.clear();
44   result->unknown_logs_scts.clear();
45 
46   bool has_verified_scts = false;
47 
48   std::string embedded_scts;
49   if (!cert->GetIntermediateCertificates().empty() &&
50       ct::ExtractEmbeddedSCTList(
51           cert->os_cert_handle(),
52           &embedded_scts)) {
53     ct::LogEntry precert_entry;
54 
55     has_verified_scts =
56         ct::GetPrecertLogEntry(
57             cert->os_cert_handle(),
58             cert->GetIntermediateCertificates().front(),
59             &precert_entry) &&
60         VerifySCTs(
61             embedded_scts,
62             precert_entry,
63             ct::SignedCertificateTimestamp::SCT_EMBEDDED,
64             result);
65   }
66 
67   std::string sct_list_from_ocsp;
68   if (!stapled_ocsp_response.empty() &&
69       !cert->GetIntermediateCertificates().empty()) {
70     ct::ExtractSCTListFromOCSPResponse(
71         cert->GetIntermediateCertificates().front(), cert->serial_number(),
72         stapled_ocsp_response, &sct_list_from_ocsp);
73   }
74 
75   // Log to Net Log, after extracting SCTs but before possibly failing on
76   // X.509 entry creation.
77   NetLog::ParametersCallback net_log_callback =
78       base::Bind(&NetLogRawSignedCertificateTimestampCallback,
79           &embedded_scts, &sct_list_from_ocsp, &sct_list_from_tls_extension);
80 
81   net_log.AddEvent(
82       NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED,
83       net_log_callback);
84 
85   ct::LogEntry x509_entry;
86   if (ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) {
87     has_verified_scts |= VerifySCTs(
88         sct_list_from_ocsp,
89         x509_entry,
90         ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
91         result);
92 
93     has_verified_scts |= VerifySCTs(
94         sct_list_from_tls_extension,
95         x509_entry,
96         ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
97         result);
98   }
99 
100   NetLog::ParametersCallback net_log_checked_callback =
101       base::Bind(&NetLogSignedCertificateTimestampCallback, result);
102 
103   net_log.AddEvent(
104       NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED,
105       net_log_checked_callback);
106 
107   if (has_verified_scts)
108     return OK;
109 
110   return ERR_CT_NO_SCTS_VERIFIED_OK;
111 }
112 
VerifySCTs(const std::string & encoded_sct_list,const ct::LogEntry & expected_entry,ct::SignedCertificateTimestamp::Origin origin,ct::CTVerifyResult * result)113 bool MultiLogCTVerifier::VerifySCTs(
114     const std::string& encoded_sct_list,
115     const ct::LogEntry& expected_entry,
116     ct::SignedCertificateTimestamp::Origin origin,
117     ct::CTVerifyResult* result) {
118   if (logs_.empty())
119     return false;
120 
121   base::StringPiece temp(encoded_sct_list);
122   std::vector<base::StringPiece> sct_list;
123 
124   if (!ct::DecodeSCTList(&temp, &sct_list))
125     return false;
126 
127   bool verified = false;
128   for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin();
129        it != sct_list.end(); ++it) {
130     base::StringPiece encoded_sct(*it);
131 
132     scoped_refptr<ct::SignedCertificateTimestamp> decoded_sct;
133     if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) {
134       // XXX(rsleevi): Should we really just skip over bad SCTs?
135       continue;
136     }
137     decoded_sct->origin = origin;
138 
139     verified |= VerifySingleSCT(decoded_sct, expected_entry, result);
140   }
141 
142   return verified;
143 }
144 
VerifySingleSCT(scoped_refptr<ct::SignedCertificateTimestamp> sct,const ct::LogEntry & expected_entry,ct::CTVerifyResult * result)145 bool MultiLogCTVerifier::VerifySingleSCT(
146     scoped_refptr<ct::SignedCertificateTimestamp> sct,
147     const ct::LogEntry& expected_entry,
148     ct::CTVerifyResult* result) {
149 
150   // Assume this SCT is untrusted until proven otherwise.
151   IDToLogMap::iterator it = logs_.find(sct->log_id);
152   if (it == logs_.end()) {
153     DVLOG(1) << "SCT does not match any known log.";
154     result->unknown_logs_scts.push_back(sct);
155     return false;
156   }
157 
158   sct->log_description = it->second->description();
159 
160   if (!it->second->Verify(expected_entry, *sct)) {
161     DVLOG(1) << "Unable to verify SCT signature.";
162     result->invalid_scts.push_back(sct);
163     return false;
164   }
165 
166   // SCT verified ok, just make sure the timestamp is legitimate.
167   if (sct->timestamp > base::Time::Now()) {
168     DVLOG(1) << "SCT is from the future!";
169     result->invalid_scts.push_back(sct);
170     return false;
171   }
172 
173   result->verified_scts.push_back(sct);
174   return true;
175 }
176 
177 } // namespace net
178