Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 "net/base/net_errors.h" | |
| 8 #include "net/cert/ct_log_verifier.h" | |
| 9 #include "net/cert/ct_objects_extractor.h" | |
| 10 #include "net/cert/ct_serialization.h" | |
| 11 #include "net/cert/ct_verify_result.h" | |
| 12 #include "net/cert/x509_certificate.h" | |
| 13 | |
| 14 namespace net { | |
| 15 | |
| 16 MultiLogCTVerifier::MultiLogCTVerifier() { } | |
| 17 | |
| 18 MultiLogCTVerifier::~MultiLogCTVerifier() { } | |
| 19 | |
| 20 void MultiLogCTVerifier::AddLog(scoped_ptr<CTLogVerifier> log_verifier) { | |
| 21 DCHECK(log_verifier); | |
| 22 if (!log_verifier) | |
| 23 return; | |
| 24 | |
| 25 linked_ptr<CTLogVerifier> log(log_verifier.release()); | |
| 26 logs_[log->key_id()] = log; | |
| 27 } | |
| 28 | |
| 29 int MultiLogCTVerifier::Verify( | |
| 30 X509Certificate* cert, | |
| 31 const std::string& sct_list_from_ocsp, | |
| 32 const std::string& sct_list_from_tls_extension, | |
| 33 ct::CTVerifyResult* result) { | |
| 34 DCHECK(cert); | |
| 35 DCHECK(result); | |
| 36 | |
| 37 result->verified_scts.clear(); | |
| 38 result->unverified_scts.clear(); | |
| 39 result->unknown_logs_scts.clear(); | |
| 40 | |
| 41 bool has_verified_scts = false; | |
| 42 | |
| 43 std::string embedded_scts; | |
| 44 if (!cert->GetIntermediateCertificates().empty() && | |
| 45 ct::ExtractEmbeddedSCTList( | |
| 46 cert->os_cert_handle(), | |
| 47 &embedded_scts)) { | |
| 48 ct::LogEntry precert_entry; | |
| 49 | |
| 50 has_verified_scts = | |
| 51 ct::GetPrecertLogEntry( | |
| 52 cert->os_cert_handle(), | |
| 53 cert->GetIntermediateCertificates().front(), | |
| 54 &precert_entry) && | |
| 55 VerifySCTs( | |
| 56 embedded_scts, | |
| 57 precert_entry, | |
| 58 ct::SignedCertificateTimestamp::SCT_EMBEDDED, | |
| 59 result); | |
| 60 } | |
| 61 | |
| 62 ct::LogEntry x509_entry; | |
| 63 if (!ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) | |
| 64 return has_verified_scts ? OK : ERR_FAILED; | |
| 65 | |
| 66 has_verified_scts |= VerifySCTs( | |
| 67 sct_list_from_ocsp, | |
| 68 x509_entry, | |
| 69 ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, | |
| 70 result); | |
| 71 | |
| 72 has_verified_scts |= VerifySCTs( | |
| 73 sct_list_from_tls_extension, | |
| 74 x509_entry, | |
| 75 ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, | |
| 76 result); | |
| 77 | |
| 78 if (has_verified_scts) | |
| 79 return OK; | |
| 80 | |
| 81 return ERR_FAILED; | |
| 82 } | |
| 83 | |
| 84 bool MultiLogCTVerifier::VerifySCTs( | |
| 85 const std::string& encoded_sct_list, | |
| 86 const ct::LogEntry& expected_entry, | |
| 87 ct::SignedCertificateTimestamp::Origin origin, | |
| 88 ct::CTVerifyResult* result) { | |
| 89 if (logs_.empty()) | |
| 90 return false; | |
| 91 | |
| 92 base::StringPiece temp(encoded_sct_list); | |
| 93 std::vector<base::StringPiece> sct_list; | |
| 94 | |
| 95 if (!ct::DecodeSCTList(&temp, &sct_list)) | |
| 96 return false; | |
| 97 | |
| 98 bool verified = false; | |
| 99 for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin(); | |
| 100 it != sct_list.end(); ++it) { | |
| 101 base::StringPiece encoded_sct(*it); | |
| 102 | |
| 103 scoped_refptr<ct::SignedCertificateTimestamp> decoded_sct; | |
| 104 if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) { | |
| 105 // XXX(rsleevi): Should we really just skip over bad SCTs? | |
| 106 continue; | |
| 107 } | |
| 108 decoded_sct->origin = origin; | |
| 109 | |
| 110 verified |= VerifySingleSCT(decoded_sct, expected_entry, result); | |
| 111 } | |
| 112 | |
| 113 return verified; | |
| 114 } | |
| 115 | |
| 116 bool MultiLogCTVerifier::VerifySingleSCT( | |
| 117 scoped_refptr<ct::SignedCertificateTimestamp> sct, | |
| 118 const ct::LogEntry& expected_entry, | |
| 119 ct::CTVerifyResult* result) { | |
| 120 | |
| 121 // Assume this SCT is untrusted until proven otherwise. | |
| 122 | |
| 123 IDToLogMap::iterator it = logs_.find(sct->log_id); | |
| 124 if (it == logs_.end()) { | |
| 125 DVLOG(1) << "SCT does not match any known log."; | |
| 126 result->unknown_logs_scts.push_back(sct); | |
| 127 return false; | |
| 128 } | |
| 129 | |
| 130 if (!it->second->Verify(expected_entry, *sct)) { | |
| 131 DVLOG(1) << "Unable to verify SCT signature."; | |
| 132 result->unverified_scts.push_back(sct); | |
| 133 return false; | |
| 134 } | |
| 135 | |
| 136 // SCT verified ok, just make sure the timestamp is legitimate. | |
| 137 // Add 1 second to allow some slack for accepting SCTs which have *Just* | |
| 138 // been issued. | |
|
wtc
2013/11/25 23:15:50
Delete the stale comment about the 1-second slack
Eran M. (Google)
2013/11/26 10:10:24
Done.
| |
| 139 if (sct->timestamp > base::Time::Now()) { | |
| 140 DVLOG(1) << "SCT is from the future!"; | |
| 141 result->unverified_scts.push_back(sct); | |
| 142 return false; | |
| 143 } | |
| 144 | |
| 145 result->verified_scts.push_back(sct); | |
| 146 return true; | |
| 147 } | |
| 148 | |
| 149 } // namespace net | |
| OLD | NEW |