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