OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 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/base/net_log.h" |
| 9 #include "net/cert/ct_log_verifier.h" |
| 10 #include "net/cert/ct_objects_extractor.h" |
| 11 #include "net/cert/ct_serialization.h" |
| 12 #include "net/cert/ct_verify_result.h" |
| 13 #include "net/cert/signed_certificate_timestamp.h" |
| 14 #include "net/cert/x509_certificate.h" |
| 15 |
| 16 namespace net { |
| 17 |
| 18 MultiLogCTVerifier::MultiLogCTVerifier(scoped_ptr<CTLogVerifier> log_verifier) { |
| 19 logs_.push_back(log_verifier.release()); |
| 20 } |
| 21 |
| 22 MultiLogCTVerifier::~MultiLogCTVerifier() { } |
| 23 |
| 24 void MultiLogCTVerifier::AddLog(scoped_ptr<CTLogVerifier> log_verifier) { |
| 25 logs_.push_back(log_verifier.release()); |
| 26 } |
| 27 |
| 28 int MultiLogCTVerifier::Verify( |
| 29 X509Certificate* verified_cert, |
| 30 const std::string& sct_list_from_ocsp, |
| 31 const std::string& sct_list_from_tls_handshake, |
| 32 ct::CTVerifyResult* result, |
| 33 const CompletionCallback& callback, |
| 34 const BoundNetLog& net_log) { |
| 35 DCHECK(verified_cert); |
| 36 DCHECK(result); |
| 37 |
| 38 result->verified_scts.clear(); |
| 39 result->unverified_scts.clear(); |
| 40 result->unknown_logs_scts.clear(); |
| 41 |
| 42 bool has_verified_scts = false; |
| 43 |
| 44 std::string embedded_scts; |
| 45 if (!verified_cert->GetIntermediateCertificates().empty() && |
| 46 ct::ExtractEmbeddedSCTList( |
| 47 verified_cert->os_cert_handle(), |
| 48 &embedded_scts)) { |
| 49 ct::LogEntry embedded_log_entry; |
| 50 |
| 51 has_verified_scts = |
| 52 ct::GetPrecertLogEntry( |
| 53 verified_cert->os_cert_handle(), |
| 54 verified_cert->GetIntermediateCertificates().front(), |
| 55 &embedded_log_entry) && |
| 56 VerifySCTs( |
| 57 embedded_scts, |
| 58 embedded_log_entry, |
| 59 ct::SignedCertificateTimestamp::SCT_EMBEDDED, |
| 60 result); |
| 61 } |
| 62 |
| 63 ct::LogEntry x509_entry; |
| 64 if (!ct::GetX509LogEntry(verified_cert->os_cert_handle(), &x509_entry)) { |
| 65 return has_verified_scts ? OK : ERR_FAILED; |
| 66 } |
| 67 |
| 68 has_verified_scts |= VerifySCTs( |
| 69 sct_list_from_ocsp, |
| 70 x509_entry, |
| 71 ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, |
| 72 result); |
| 73 |
| 74 has_verified_scts |= VerifySCTs( |
| 75 sct_list_from_tls_handshake, |
| 76 x509_entry, |
| 77 ct::SignedCertificateTimestamp::SCT_FROM_TLS_HANDSHAKE, |
| 78 result); |
| 79 |
| 80 //XXX(eranm): Add a specific error code to indicate no presence |
| 81 // of SCTs at all. |
| 82 return has_verified_scts ? OK : ERR_FAILED; |
| 83 } |
| 84 |
| 85 bool MultiLogCTVerifier::VerifySCTs( |
| 86 const std::string& encoded_sct_list, |
| 87 const ct::LogEntry& expected_entry, |
| 88 ct::SignedCertificateTimestamp::Origin origin, |
| 89 ct::CTVerifyResult* result) { |
| 90 if (logs_.empty()) |
| 91 return false; |
| 92 |
| 93 base::StringPiece temp(encoded_sct_list); |
| 94 std::vector<base::StringPiece> sct_list; |
| 95 |
| 96 if (!ct::DecodeSCTList(&temp, &sct_list)) |
| 97 return false; |
| 98 |
| 99 bool verified = false; |
| 100 for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin(); |
| 101 it != sct_list.end(); ++it) { |
| 102 base::StringPiece encoded_sct(*it); |
| 103 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 const ct::SignedCertificateTimestamp& sct, |
| 118 const ct::LogEntry& expected_entry, |
| 119 ct::CTVerifyResult* result) { |
| 120 |
| 121 // Assume this SCT is untrusted until proven otherwise. |
| 122 result->unverified_scts.push_back(sct); |
| 123 CTLogVerifier::VerifyResult verify_result = |
| 124 CTLogVerifier::SCT_NOT_FROM_THIS_LOG; |
| 125 |
| 126 for (ScopedVector<CTLogVerifier>::iterator it = logs_.begin(); |
| 127 it != logs_.end() && |
| 128 (verify_result == CTLogVerifier::SCT_NOT_FROM_THIS_LOG); |
| 129 ++it) { |
| 130 verify_result = (*it)->Verify(expected_entry, sct); |
| 131 } |
| 132 |
| 133 if (verify_result == CTLogVerifier::SCT_NOT_FROM_THIS_LOG) { |
| 134 DVLOG(1) << "SCT does not match any known log."; |
| 135 result->unverified_scts.pop_back(); |
| 136 result->unknown_logs_scts.push_back(sct); |
| 137 return false; |
| 138 } else if (verify_result != CTLogVerifier::SCT_VERIFIED_OK) { |
| 139 DVLOG(1) << "Unable to verify SCT signature."; |
| 140 return false; |
| 141 } |
| 142 |
| 143 // verify_result is SCT_VERIFIED_OK, just make sure the timestamp is |
| 144 // legitimate. |
| 145 if (sct.timestamp + base::TimeDelta::FromSeconds(1) > base::Time::Now()) { |
| 146 DVLOG(1) << "SCT is from the future!"; |
| 147 return false; |
| 148 } |
| 149 |
| 150 result->unverified_scts.pop_back(); |
| 151 result->verified_scts.push_back(sct); |
| 152 return true; |
| 153 } |
| 154 |
| 155 } // namespace net |
OLD | NEW |