| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/multi_log_ct_verifier.h" | 5 #include "net/cert/multi_log_ct_verifier.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 result.invalid_scts.size() + | 49 result.invalid_scts.size() + |
| 50 result.verified_scts.size() + | 50 result.verified_scts.size() + |
| 51 result.unknown_logs_scts.size(), | 51 result.unknown_logs_scts.size(), |
| 52 1, | 52 1, |
| 53 10, | 53 10, |
| 54 11); | 54 11); |
| 55 } | 55 } |
| 56 | 56 |
| 57 } // namespace | 57 } // namespace |
| 58 | 58 |
| 59 MultiLogCTVerifier::MultiLogCTVerifier() { } | 59 MultiLogCTVerifier::MultiLogCTVerifier() : observer_(nullptr) { |
| 60 } |
| 60 | 61 |
| 61 MultiLogCTVerifier::~MultiLogCTVerifier() { } | 62 MultiLogCTVerifier::~MultiLogCTVerifier() { } |
| 62 | 63 |
| 63 void MultiLogCTVerifier::AddLogs( | 64 void MultiLogCTVerifier::AddLogs( |
| 64 const std::vector<scoped_refptr<CTLogVerifier>>& log_verifiers) { | 65 const std::vector<scoped_refptr<CTLogVerifier>>& log_verifiers) { |
| 65 for (const auto& log_verifier : log_verifiers) { | 66 for (const auto& log_verifier : log_verifiers) { |
| 66 VLOG(1) << "Adding CT log: " << log_verifier->description(); | 67 VLOG(1) << "Adding CT log: " << log_verifier->description(); |
| 67 logs_[log_verifier->key_id()] = log_verifier; | 68 logs_[log_verifier->key_id()] = log_verifier; |
| 68 } | 69 } |
| 69 } | 70 } |
| 70 | 71 |
| 72 void MultiLogCTVerifier::SetObserver(Observer* observer) { |
| 73 observer_ = observer; |
| 74 } |
| 75 |
| 71 int MultiLogCTVerifier::Verify( | 76 int MultiLogCTVerifier::Verify( |
| 72 X509Certificate* cert, | 77 X509Certificate* cert, |
| 73 const std::string& stapled_ocsp_response, | 78 const std::string& stapled_ocsp_response, |
| 74 const std::string& sct_list_from_tls_extension, | 79 const std::string& sct_list_from_tls_extension, |
| 75 ct::CTVerifyResult* result, | 80 ct::CTVerifyResult* result, |
| 76 const BoundNetLog& net_log) { | 81 const BoundNetLog& net_log) { |
| 77 DCHECK(cert); | 82 DCHECK(cert); |
| 78 DCHECK(result); | 83 DCHECK(result); |
| 79 | 84 |
| 80 result->verified_scts.clear(); | 85 result->verified_scts.clear(); |
| 81 result->invalid_scts.clear(); | 86 result->invalid_scts.clear(); |
| 82 result->unknown_logs_scts.clear(); | 87 result->unknown_logs_scts.clear(); |
| 83 | 88 |
| 84 bool has_verified_scts = false; | 89 bool has_verified_scts = false; |
| 85 | 90 |
| 86 std::string embedded_scts; | 91 std::string embedded_scts; |
| 87 if (!cert->GetIntermediateCertificates().empty() && | 92 if (!cert->GetIntermediateCertificates().empty() && |
| 88 ct::ExtractEmbeddedSCTList( | 93 ct::ExtractEmbeddedSCTList( |
| 89 cert->os_cert_handle(), | 94 cert->os_cert_handle(), |
| 90 &embedded_scts)) { | 95 &embedded_scts)) { |
| 91 ct::LogEntry precert_entry; | 96 ct::LogEntry precert_entry; |
| 92 | 97 |
| 93 has_verified_scts = | 98 has_verified_scts = |
| 94 ct::GetPrecertLogEntry( | 99 ct::GetPrecertLogEntry(cert->os_cert_handle(), |
| 95 cert->os_cert_handle(), | 100 cert->GetIntermediateCertificates().front(), |
| 96 cert->GetIntermediateCertificates().front(), | 101 &precert_entry) && |
| 97 &precert_entry) && | 102 VerifySCTs(embedded_scts, precert_entry, |
| 98 VerifySCTs( | 103 ct::SignedCertificateTimestamp::SCT_EMBEDDED, cert, result); |
| 99 embedded_scts, | |
| 100 precert_entry, | |
| 101 ct::SignedCertificateTimestamp::SCT_EMBEDDED, | |
| 102 result); | |
| 103 } | 104 } |
| 104 | 105 |
| 105 std::string sct_list_from_ocsp; | 106 std::string sct_list_from_ocsp; |
| 106 if (!stapled_ocsp_response.empty() && | 107 if (!stapled_ocsp_response.empty() && |
| 107 !cert->GetIntermediateCertificates().empty()) { | 108 !cert->GetIntermediateCertificates().empty()) { |
| 108 ct::ExtractSCTListFromOCSPResponse( | 109 ct::ExtractSCTListFromOCSPResponse( |
| 109 cert->GetIntermediateCertificates().front(), cert->serial_number(), | 110 cert->GetIntermediateCertificates().front(), cert->serial_number(), |
| 110 stapled_ocsp_response, &sct_list_from_ocsp); | 111 stapled_ocsp_response, &sct_list_from_ocsp); |
| 111 } | 112 } |
| 112 | 113 |
| 113 // Log to Net Log, after extracting SCTs but before possibly failing on | 114 // Log to Net Log, after extracting SCTs but before possibly failing on |
| 114 // X.509 entry creation. | 115 // X.509 entry creation. |
| 115 NetLog::ParametersCallback net_log_callback = | 116 NetLog::ParametersCallback net_log_callback = |
| 116 base::Bind(&NetLogRawSignedCertificateTimestampCallback, | 117 base::Bind(&NetLogRawSignedCertificateTimestampCallback, |
| 117 &embedded_scts, &sct_list_from_ocsp, &sct_list_from_tls_extension); | 118 &embedded_scts, &sct_list_from_ocsp, &sct_list_from_tls_extension); |
| 118 | 119 |
| 119 net_log.AddEvent( | 120 net_log.AddEvent( |
| 120 NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED, | 121 NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED, |
| 121 net_log_callback); | 122 net_log_callback); |
| 122 | 123 |
| 123 ct::LogEntry x509_entry; | 124 ct::LogEntry x509_entry; |
| 124 if (ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) { | 125 if (ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) { |
| 125 has_verified_scts |= VerifySCTs( | 126 has_verified_scts |= VerifySCTs( |
| 126 sct_list_from_ocsp, | 127 sct_list_from_ocsp, x509_entry, |
| 127 x509_entry, | 128 ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, cert, result); |
| 128 ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, | |
| 129 result); | |
| 130 | 129 |
| 131 has_verified_scts |= VerifySCTs( | 130 has_verified_scts |= VerifySCTs( |
| 132 sct_list_from_tls_extension, | 131 sct_list_from_tls_extension, x509_entry, |
| 133 x509_entry, | 132 ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, cert, result); |
| 134 ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, | |
| 135 result); | |
| 136 } | 133 } |
| 137 | 134 |
| 138 NetLog::ParametersCallback net_log_checked_callback = | 135 NetLog::ParametersCallback net_log_checked_callback = |
| 139 base::Bind(&NetLogSignedCertificateTimestampCallback, result); | 136 base::Bind(&NetLogSignedCertificateTimestampCallback, result); |
| 140 | 137 |
| 141 net_log.AddEvent( | 138 net_log.AddEvent( |
| 142 NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED, | 139 NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED, |
| 143 net_log_checked_callback); | 140 net_log_checked_callback); |
| 144 | 141 |
| 145 LogNumSCTsToUMA(*result); | 142 LogNumSCTsToUMA(*result); |
| 146 | 143 |
| 147 if (has_verified_scts) | 144 if (has_verified_scts) |
| 148 return OK; | 145 return OK; |
| 149 | 146 |
| 150 return ERR_CT_NO_SCTS_VERIFIED_OK; | 147 return ERR_CT_NO_SCTS_VERIFIED_OK; |
| 151 } | 148 } |
| 152 | 149 |
| 153 bool MultiLogCTVerifier::VerifySCTs( | 150 bool MultiLogCTVerifier::VerifySCTs( |
| 154 const std::string& encoded_sct_list, | 151 const std::string& encoded_sct_list, |
| 155 const ct::LogEntry& expected_entry, | 152 const ct::LogEntry& expected_entry, |
| 156 ct::SignedCertificateTimestamp::Origin origin, | 153 ct::SignedCertificateTimestamp::Origin origin, |
| 154 X509Certificate* cert, |
| 157 ct::CTVerifyResult* result) { | 155 ct::CTVerifyResult* result) { |
| 158 if (logs_.empty()) | 156 if (logs_.empty()) |
| 159 return false; | 157 return false; |
| 160 | 158 |
| 161 base::StringPiece temp(encoded_sct_list); | 159 base::StringPiece temp(encoded_sct_list); |
| 162 std::vector<base::StringPiece> sct_list; | 160 std::vector<base::StringPiece> sct_list; |
| 163 | 161 |
| 164 if (!ct::DecodeSCTList(&temp, &sct_list)) | 162 if (!ct::DecodeSCTList(&temp, &sct_list)) |
| 165 return false; | 163 return false; |
| 166 | 164 |
| 167 bool verified = false; | 165 bool verified = false; |
| 168 for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin(); | 166 for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin(); |
| 169 it != sct_list.end(); ++it) { | 167 it != sct_list.end(); ++it) { |
| 170 base::StringPiece encoded_sct(*it); | 168 base::StringPiece encoded_sct(*it); |
| 171 LogSCTOriginToUMA(origin); | 169 LogSCTOriginToUMA(origin); |
| 172 | 170 |
| 173 scoped_refptr<ct::SignedCertificateTimestamp> decoded_sct; | 171 scoped_refptr<ct::SignedCertificateTimestamp> decoded_sct; |
| 174 if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) { | 172 if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) { |
| 175 LogSCTStatusToUMA(ct::SCT_STATUS_NONE); | 173 LogSCTStatusToUMA(ct::SCT_STATUS_NONE); |
| 176 // XXX(rsleevi): Should we really just skip over bad SCTs? | 174 // XXX(rsleevi): Should we really just skip over bad SCTs? |
| 177 continue; | 175 continue; |
| 178 } | 176 } |
| 179 decoded_sct->origin = origin; | 177 decoded_sct->origin = origin; |
| 180 | 178 |
| 181 verified |= VerifySingleSCT(decoded_sct, expected_entry, result); | 179 verified |= VerifySingleSCT(decoded_sct, expected_entry, cert, result); |
| 182 } | 180 } |
| 183 | 181 |
| 184 return verified; | 182 return verified; |
| 185 } | 183 } |
| 186 | 184 |
| 187 bool MultiLogCTVerifier::VerifySingleSCT( | 185 bool MultiLogCTVerifier::VerifySingleSCT( |
| 188 scoped_refptr<ct::SignedCertificateTimestamp> sct, | 186 scoped_refptr<ct::SignedCertificateTimestamp> sct, |
| 189 const ct::LogEntry& expected_entry, | 187 const ct::LogEntry& expected_entry, |
| 188 X509Certificate* cert, |
| 190 ct::CTVerifyResult* result) { | 189 ct::CTVerifyResult* result) { |
| 191 | |
| 192 // Assume this SCT is untrusted until proven otherwise. | 190 // Assume this SCT is untrusted until proven otherwise. |
| 193 const auto& it = logs_.find(sct->log_id); | 191 const auto& it = logs_.find(sct->log_id); |
| 194 if (it == logs_.end()) { | 192 if (it == logs_.end()) { |
| 195 DVLOG(1) << "SCT does not match any known log."; | 193 DVLOG(1) << "SCT does not match any known log."; |
| 196 result->unknown_logs_scts.push_back(sct); | 194 result->unknown_logs_scts.push_back(sct); |
| 197 LogSCTStatusToUMA(ct::SCT_STATUS_LOG_UNKNOWN); | 195 LogSCTStatusToUMA(ct::SCT_STATUS_LOG_UNKNOWN); |
| 198 return false; | 196 return false; |
| 199 } | 197 } |
| 200 | 198 |
| 201 sct->log_description = it->second->description(); | 199 sct->log_description = it->second->description(); |
| 202 | 200 |
| 203 if (!it->second->Verify(expected_entry, *sct.get())) { | 201 if (!it->second->Verify(expected_entry, *sct.get())) { |
| 204 DVLOG(1) << "Unable to verify SCT signature."; | 202 DVLOG(1) << "Unable to verify SCT signature."; |
| 205 result->invalid_scts.push_back(sct); | 203 result->invalid_scts.push_back(sct); |
| 206 LogSCTStatusToUMA(ct::SCT_STATUS_INVALID); | 204 LogSCTStatusToUMA(ct::SCT_STATUS_INVALID); |
| 207 return false; | 205 return false; |
| 208 } | 206 } |
| 209 | 207 |
| 210 // SCT verified ok, just make sure the timestamp is legitimate. | 208 // SCT verified ok, just make sure the timestamp is legitimate. |
| 211 if (sct->timestamp > base::Time::Now()) { | 209 if (sct->timestamp > base::Time::Now()) { |
| 212 DVLOG(1) << "SCT is from the future!"; | 210 DVLOG(1) << "SCT is from the future!"; |
| 213 result->invalid_scts.push_back(sct); | 211 result->invalid_scts.push_back(sct); |
| 214 LogSCTStatusToUMA(ct::SCT_STATUS_INVALID); | 212 LogSCTStatusToUMA(ct::SCT_STATUS_INVALID); |
| 215 return false; | 213 return false; |
| 216 } | 214 } |
| 217 | 215 |
| 218 LogSCTStatusToUMA(ct::SCT_STATUS_OK); | 216 LogSCTStatusToUMA(ct::SCT_STATUS_OK); |
| 219 result->verified_scts.push_back(sct); | 217 result->verified_scts.push_back(sct); |
| 218 if (observer_) |
| 219 observer_->OnSCTVerified(cert, sct.get()); |
| 220 return true; | 220 return true; |
| 221 } | 221 } |
| 222 | 222 |
| 223 } // namespace net | 223 } // namespace net |
| OLD | NEW |