| Index: net/cert/multi_log_ct_verifier.cc
|
| diff --git a/net/cert/multi_log_ct_verifier.cc b/net/cert/multi_log_ct_verifier.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d2211e53bace6ff377a3058db002807ce607cb85
|
| --- /dev/null
|
| +++ b/net/cert/multi_log_ct_verifier.cc
|
| @@ -0,0 +1,155 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/cert/multi_log_ct_verifier.h"
|
| +
|
| +#include "net/base/net_errors.h"
|
| +#include "net/base/net_log.h"
|
| +#include "net/cert/ct_log_verifier.h"
|
| +#include "net/cert/ct_objects_extractor.h"
|
| +#include "net/cert/ct_serialization.h"
|
| +#include "net/cert/ct_verify_result.h"
|
| +#include "net/cert/signed_certificate_timestamp.h"
|
| +#include "net/cert/x509_certificate.h"
|
| +
|
| +namespace net {
|
| +
|
| +MultiLogCTVerifier::MultiLogCTVerifier(scoped_ptr<CTLogVerifier> log_verifier) {
|
| + logs_.push_back(log_verifier.release());
|
| +}
|
| +
|
| +MultiLogCTVerifier::~MultiLogCTVerifier() { }
|
| +
|
| +void MultiLogCTVerifier::AddLog(scoped_ptr<CTLogVerifier> log_verifier) {
|
| + logs_.push_back(log_verifier.release());
|
| +}
|
| +
|
| +int MultiLogCTVerifier::Verify(
|
| + X509Certificate* verified_cert,
|
| + const std::string& sct_list_from_ocsp,
|
| + const std::string& sct_list_from_tls_handshake,
|
| + ct::CTVerifyResult* result,
|
| + const CompletionCallback& callback,
|
| + const BoundNetLog& net_log) {
|
| + DCHECK(verified_cert);
|
| + DCHECK(result);
|
| +
|
| + result->verified_scts.clear();
|
| + result->unverified_scts.clear();
|
| + result->unknown_logs_scts.clear();
|
| +
|
| + bool has_verified_scts = false;
|
| +
|
| + std::string embedded_scts;
|
| + if (!verified_cert->GetIntermediateCertificates().empty() &&
|
| + ct::ExtractEmbeddedSCTList(
|
| + verified_cert->os_cert_handle(),
|
| + &embedded_scts)) {
|
| + ct::LogEntry embedded_log_entry;
|
| +
|
| + has_verified_scts =
|
| + ct::GetPrecertLogEntry(
|
| + verified_cert->os_cert_handle(),
|
| + verified_cert->GetIntermediateCertificates().front(),
|
| + &embedded_log_entry) &&
|
| + VerifySCTs(
|
| + embedded_scts,
|
| + embedded_log_entry,
|
| + ct::SignedCertificateTimestamp::SCT_EMBEDDED,
|
| + result);
|
| + }
|
| +
|
| + ct::LogEntry x509_entry;
|
| + if (!ct::GetX509LogEntry(verified_cert->os_cert_handle(), &x509_entry)) {
|
| + return has_verified_scts ? OK : ERR_FAILED;
|
| + }
|
| +
|
| + has_verified_scts |= VerifySCTs(
|
| + sct_list_from_ocsp,
|
| + x509_entry,
|
| + ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
|
| + result);
|
| +
|
| + has_verified_scts |= VerifySCTs(
|
| + sct_list_from_tls_handshake,
|
| + x509_entry,
|
| + ct::SignedCertificateTimestamp::SCT_FROM_TLS_HANDSHAKE,
|
| + result);
|
| +
|
| + //XXX(eranm): Add a specific error code to indicate no presence
|
| + // of SCTs at all.
|
| + return has_verified_scts ? OK : ERR_FAILED;
|
| +}
|
| +
|
| +bool MultiLogCTVerifier::VerifySCTs(
|
| + const std::string& encoded_sct_list,
|
| + const ct::LogEntry& expected_entry,
|
| + ct::SignedCertificateTimestamp::Origin origin,
|
| + ct::CTVerifyResult* result) {
|
| + if (logs_.empty())
|
| + return false;
|
| +
|
| + base::StringPiece temp(encoded_sct_list);
|
| + std::vector<base::StringPiece> sct_list;
|
| +
|
| + if (!ct::DecodeSCTList(&temp, &sct_list))
|
| + return false;
|
| +
|
| + bool verified = false;
|
| + for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin();
|
| + it != sct_list.end(); ++it) {
|
| + base::StringPiece encoded_sct(*it);
|
| + ct::SignedCertificateTimestamp decoded_sct;
|
| + if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) {
|
| + // XXX(rsleevi): Should we really just skip over bad SCTs?
|
| + continue;
|
| + }
|
| + decoded_sct.origin = origin;
|
| +
|
| + verified |= VerifySingleSCT(decoded_sct, expected_entry, result);
|
| + }
|
| +
|
| + return verified;
|
| +}
|
| +
|
| +bool MultiLogCTVerifier::VerifySingleSCT(
|
| + const ct::SignedCertificateTimestamp& sct,
|
| + const ct::LogEntry& expected_entry,
|
| + ct::CTVerifyResult* result) {
|
| +
|
| + // Assume this SCT is untrusted until proven otherwise.
|
| + result->unverified_scts.push_back(sct);
|
| + CTLogVerifier::VerifyResult verify_result =
|
| + CTLogVerifier::SCT_NOT_FROM_THIS_LOG;
|
| +
|
| + for (ScopedVector<CTLogVerifier>::iterator it = logs_.begin();
|
| + it != logs_.end() &&
|
| + (verify_result == CTLogVerifier::SCT_NOT_FROM_THIS_LOG);
|
| + ++it) {
|
| + verify_result = (*it)->Verify(expected_entry, sct);
|
| + }
|
| +
|
| + if (verify_result == CTLogVerifier::SCT_NOT_FROM_THIS_LOG) {
|
| + DVLOG(1) << "SCT does not match any known log.";
|
| + result->unverified_scts.pop_back();
|
| + result->unknown_logs_scts.push_back(sct);
|
| + return false;
|
| + } else if (verify_result != CTLogVerifier::SCT_VERIFIED_OK) {
|
| + DVLOG(1) << "Unable to verify SCT signature.";
|
| + return false;
|
| + }
|
| +
|
| + // verify_result is SCT_VERIFIED_OK, just make sure the timestamp is
|
| + // legitimate.
|
| + if (sct.timestamp + base::TimeDelta::FromSeconds(1) > base::Time::Now()) {
|
| + DVLOG(1) << "SCT is from the future!";
|
| + return false;
|
| + }
|
| +
|
| + result->unverified_scts.pop_back();
|
| + result->verified_scts.push_back(sct);
|
| + return true;
|
| +}
|
| +
|
| +} // namespace net
|
|
|