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 if (!log_verifier) | |
| 22 return; | |
|
wtc
2013/11/21 23:26:34
Are you sure we need to allow a null |log_verifier
Eran M. (Google)
2013/11/23 21:02:07
No, but I wouldn't want to crash here in productio
wtc
2013/11/25 23:15:50
A crash may help expose a bug sooner. If we know n
| |
| 23 | |
| 24 std::string log_id(log_verifier->key_id()); | |
| 25 logs_[log_id].reset(log_verifier.release()); | |
| 26 } | |
| 27 | |
| 28 int MultiLogCTVerifier::Verify( | |
| 29 X509Certificate* cert, | |
| 30 const std::string& sct_list_from_ocsp, | |
| 31 const std::string& sct_list_from_tls_extension, | |
| 32 ct::CTVerifyResult* result) { | |
| 33 DCHECK(cert); | |
| 34 DCHECK(result); | |
| 35 | |
| 36 result->verified_scts.clear(); | |
| 37 result->unverified_scts.clear(); | |
| 38 result->unknown_logs_scts.clear(); | |
| 39 | |
| 40 bool has_verified_scts = false; | |
| 41 | |
| 42 std::string embedded_scts; | |
| 43 if (!cert->GetIntermediateCertificates().empty() && | |
| 44 ct::ExtractEmbeddedSCTList( | |
| 45 cert->os_cert_handle(), | |
| 46 &embedded_scts)) { | |
| 47 ct::LogEntry precert_entry; | |
| 48 | |
| 49 has_verified_scts = | |
| 50 ct::GetPrecertLogEntry( | |
| 51 cert->os_cert_handle(), | |
| 52 cert->GetIntermediateCertificates().front(), | |
| 53 &precert_entry) && | |
| 54 VerifySCTs( | |
| 55 embedded_scts, | |
| 56 precert_entry, | |
| 57 ct::SignedCertificateTimestamp::SCT_EMBEDDED, | |
| 58 result); | |
| 59 } | |
| 60 | |
| 61 ct::LogEntry x509_entry; | |
| 62 if (!ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) | |
| 63 return has_verified_scts ? OK : ERR_CT_LOG_ENTRY_CREATION_FAILED; | |
| 64 | |
| 65 has_verified_scts |= VerifySCTs( | |
| 66 sct_list_from_ocsp, | |
| 67 x509_entry, | |
| 68 ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, | |
| 69 result); | |
| 70 | |
| 71 has_verified_scts |= VerifySCTs( | |
| 72 sct_list_from_tls_extension, | |
| 73 x509_entry, | |
| 74 ct::SignedCertificateTimestamp::SCT_FROM_TLS_HANDSHAKE, | |
| 75 result); | |
| 76 | |
| 77 if (has_verified_scts) | |
| 78 return OK; | |
| 79 | |
| 80 if (!result->unverified_scts.empty()) | |
| 81 return ERR_NO_SCTS_VERIFIED_OK; | |
| 82 | |
| 83 if (!result->unknown_logs_scts.empty()) | |
| 84 return ERR_NO_SCTS_FROM_KNOWN_LOGS; | |
| 85 | |
| 86 return ERR_NO_SCTS_PRESENT; | |
|
wtc
2013/11/21 23:26:34
It should be sufficient to just use one error code
Eran M. (Google)
2013/11/23 21:02:07
Will be done in the next patch, when I introduce t
| |
| 87 } | |
| 88 | |
| 89 bool MultiLogCTVerifier::VerifySCTs( | |
| 90 const std::string& encoded_sct_list, | |
| 91 const ct::LogEntry& expected_entry, | |
| 92 ct::SignedCertificateTimestamp::Origin origin, | |
| 93 ct::CTVerifyResult* result) { | |
| 94 if (logs_.empty()) | |
| 95 return false; | |
| 96 | |
| 97 base::StringPiece temp(encoded_sct_list); | |
| 98 std::vector<base::StringPiece> sct_list; | |
| 99 | |
| 100 if (!ct::DecodeSCTList(&temp, &sct_list)) | |
| 101 return false; | |
| 102 | |
| 103 bool verified = false; | |
| 104 for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin(); | |
| 105 it != sct_list.end(); ++it) { | |
| 106 base::StringPiece encoded_sct(*it); | |
| 107 ct::SignedCertificateTimestamp decoded_sct; | |
| 108 if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) { | |
| 109 // XXX(rsleevi): Should we really just skip over bad SCTs? | |
| 110 continue; | |
| 111 } | |
| 112 decoded_sct.origin = origin; | |
| 113 | |
| 114 verified |= VerifySingleSCT(decoded_sct, expected_entry, result); | |
| 115 } | |
| 116 | |
| 117 return verified; | |
| 118 } | |
| 119 | |
| 120 bool MultiLogCTVerifier::VerifySingleSCT( | |
| 121 const ct::SignedCertificateTimestamp& sct, | |
| 122 const ct::LogEntry& expected_entry, | |
| 123 ct::CTVerifyResult* result) { | |
| 124 | |
| 125 // Assume this SCT is untrusted until proven otherwise. | |
| 126 | |
| 127 IDToLogMap::iterator it = logs_.find(sct.log_id); | |
| 128 if (it == logs_.end()) { | |
| 129 DVLOG(1) << "SCT does not match any known log."; | |
| 130 result->unknown_logs_scts.push_back(sct); | |
| 131 return false; | |
| 132 } | |
| 133 | |
| 134 if (!it->second->Verify(expected_entry, sct)) { | |
| 135 DVLOG(1) << "Unable to verify SCT signature."; | |
| 136 result->unverified_scts.push_back(sct); | |
| 137 return false; | |
| 138 } | |
| 139 | |
| 140 // SCT verified ok, just make sure the timestamp is legitimate. | |
| 141 // Add 1 second to allow some slack for accepting SCTs which have *Just* | |
| 142 // been issued. | |
|
wtc
2013/11/21 23:26:34
1. The comment in the reference implementation say
Eran M. (Google)
2013/11/23 21:02:07
I've dropped this 1 second interval entirely. You'
| |
| 143 if (sct.timestamp + base::TimeDelta::FromSeconds(1) > base::Time::Now()) { | |
| 144 DVLOG(1) << "SCT is from the future!"; | |
| 145 result->unverified_scts.push_back(sct); | |
| 146 return false; | |
| 147 } | |
| 148 | |
| 149 result->verified_scts.push_back(sct); | |
| 150 return true; | |
| 151 } | |
| 152 | |
| 153 } // namespace net | |
| OLD | NEW |