diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-24 17:20:49 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-24 17:20:49 +0000 |
commit | 361fe8abbf9d24b4f7d6dfe011034205b8a57c01 (patch) | |
tree | a820073fa20ebb5a9d8288e1444e27c9d4c39553 | |
parent | 97b37f0dfa7883a1457534d9c2e3702361bad3ce (diff) | |
download | chromium_src-361fe8abbf9d24b4f7d6dfe011034205b8a57c01.zip chromium_src-361fe8abbf9d24b4f7d6dfe011034205b8a57c01.tar.gz chromium_src-361fe8abbf9d24b4f7d6dfe011034205b8a57c01.tar.bz2 |
net: Implement DNS certificate provenance check uploads.
BUG=none
TEST=none
http://codereview.chromium.org/4830001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67275 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/io_thread.cc | 5 | ||||
-rw-r--r-- | chrome/browser/net/chrome_dns_cert_provenance_checker.cc | 73 | ||||
-rw-r--r-- | net/socket/dns_cert_provenance_checker.cc | 44 | ||||
-rw-r--r-- | net/socket/dns_cert_provenance_checker.h | 2 | ||||
-rw-r--r-- | net/url_request/url_request.h | 6 |
5 files changed, 123 insertions, 7 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index a623019..1067bf8 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -380,6 +380,11 @@ void IOThread::CleanUp() { url_request_context_getters.begin(); it != url_request_context_getters.end(); ++it) { ChromeURLRequestContextGetter* getter = *it; + // Stop all pending certificate provenance check uploads + net::DnsCertProvenanceChecker* checker = + getter->GetURLRequestContext()->dns_cert_checker(); + if (checker) + checker->Shutdown(); getter->ReleaseURLRequestContext(); } diff --git a/chrome/browser/net/chrome_dns_cert_provenance_checker.cc b/chrome/browser/net/chrome_dns_cert_provenance_checker.cc index 2f6ebc5..e9bcf2f 100644 --- a/chrome/browser/net/chrome_dns_cert_provenance_checker.cc +++ b/chrome/browser/net/chrome_dns_cert_provenance_checker.cc @@ -4,6 +4,11 @@ #include "chrome/browser/net/chrome_dns_cert_provenance_checker.h" +#include "base/scoped_ptr.h" +#include "base/stl_util-inl.h" +#include "chrome/browser/net/chrome_url_request_context.h" +#include "net/url_request/url_request.h" + namespace { class ChromeDnsCertProvenanceChecker : @@ -14,7 +19,13 @@ class ChromeDnsCertProvenanceChecker : net::DnsRRResolver* dnsrr_resolver, ChromeURLRequestContext* url_req_context) : dnsrr_resolver_(dnsrr_resolver), - url_req_context_(url_req_context) { + url_req_context_(url_req_context), + upload_url_("http://chromecertcheck.appspot.com/upload"), + delegate_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + } + + ~ChromeDnsCertProvenanceChecker() { + DCHECK(inflight_requests_.empty()); } // DnsCertProvenanceChecker interface @@ -25,16 +36,74 @@ class ChromeDnsCertProvenanceChecker : dnsrr_resolver_, this); } + virtual void Shutdown() { + STLDeleteContainerPointers(inflight_requests_.begin(), + inflight_requests_.end()); + inflight_requests_.clear(); + } + // DnsCertProvenanceChecker::Delegate interface virtual void OnDnsCertLookupFailed( const std::string& hostname, const std::vector<std::string>& der_certs) { - // Currently unimplemented. + const std::string report = BuildEncryptedReport(hostname, der_certs); + + URLRequest* url_request(new URLRequest(upload_url_, &delegate_)); + url_request->set_context(url_req_context_); + url_request->set_method("POST"); + url_request->AppendBytesToUpload(report.data(), report.size()); + net::HttpRequestHeaders headers; + headers.SetHeader(net::HttpRequestHeaders::kContentType, + "x-application/chrome-cert-provenance-report"); + url_request->SetExtraRequestHeaders(headers); + inflight_requests_.insert(url_request); + url_request->Start(); } private: + void RequestComplete(URLRequest* request) { + std::set<URLRequest*>::iterator i = inflight_requests_.find(request); + DCHECK(i != inflight_requests_.end()); + delete *i; + inflight_requests_.erase(i); + } + + // URLRequestDelegate is the delegate for the upload. Since this is a + // fire-and-forget operation, we don't care if there are any errors in the + // upload. + class URLRequestDelegate : public URLRequest::Delegate { + public: + explicit URLRequestDelegate(ChromeDnsCertProvenanceChecker* checker) + : checker_(checker) { + } + + // Delegate implementation + void OnResponseStarted(URLRequest* request) { + const URLRequestStatus& status(request->status()); + if (!status.is_success()) { + LOG(WARNING) << "Certificate upload failed" + << " status:" << status.status() + << " os_error:" << status.os_error(); + } else if (request->GetResponseCode() != 200) { + LOG(WARNING) << "Certificate upload HTTP status: " + << request->GetResponseCode(); + } + checker_->RequestComplete(request); + } + + void OnReadCompleted(URLRequest* request, int bytes_read) { + NOTREACHED(); + } + + private: + ChromeDnsCertProvenanceChecker* const checker_; + }; + net::DnsRRResolver* const dnsrr_resolver_; ChromeURLRequestContext* const url_req_context_; + const GURL upload_url_; + URLRequestDelegate delegate_; + std::set<URLRequest*> inflight_requests_; }; } // namespace diff --git a/net/socket/dns_cert_provenance_checker.cc b/net/socket/dns_cert_provenance_checker.cc index 97265f1..27c4982 100644 --- a/net/socket/dns_cert_provenance_checker.cc +++ b/net/socket/dns_cert_provenance_checker.cc @@ -13,6 +13,7 @@ #include <pk11pub.h> #include <sechash.h> +#include <set> #include <string> #include "base/basictypes.h" @@ -21,6 +22,7 @@ #include "base/non_thread_safe.h" #include "base/pickle.h" #include "base/scoped_ptr.h" +#include "base/singleton.h" #include "net/base/completion_callback.h" #include "net/base/dns_util.h" #include "net/base/dnsrr_resolver.h" @@ -43,6 +45,40 @@ const uint8 kServerPublicKey[] = { 0x6c, 0x2e, 0xfb, 0x32, 0x42, 0x27, 0xe4, 0x23, 0xea, 0xcd, 0x81, 0x62, 0xc1, }; +const unsigned kMaxUploadsPerSession = 10; + +// DnsCertLimits is a singleton class which keeps track of which hosts we have +// uploaded reports for in this session. Since some users will be behind MITM +// proxies, they would otherwise upload for every host and we don't wish to +// spam the upload server. +class DnsCertLimits { + public: + DnsCertLimits() { } + + // HaveReachedMaxUploads returns true iff we have uploaded the maximum number + // of DNS certificate reports for this session. + bool HaveReachedMaxUploads() { + return uploaded_hostnames_.size() >= kMaxUploadsPerSession; + } + + // HaveReachedMaxUploads returns true iff we have already uploaded a report + // about the given hostname in this session. + bool HaveUploadedForHostname(const std::string& hostname) { + return uploaded_hostnames_.count(hostname) > 0; + } + + void DidUpload(const std::string& hostname) { + uploaded_hostnames_.insert(hostname); + } + + private: + friend struct DefaultSingletonTraits<DnsCertLimits>; + + std::set<std::string> uploaded_hostnames_; + + DISALLOW_COPY_AND_ASSIGN(DnsCertLimits); +}; + // DnsCertProvenanceCheck performs the DNS lookup of the certificate. This // class is self-deleting. class DnsCertProvenanceCheck : public NonThreadSafe { @@ -69,6 +105,12 @@ class DnsCertProvenanceCheck : public NonThreadSafe { if (der_certs_.empty()) return; + DnsCertLimits* const limits = Singleton<DnsCertLimits>::get(); + if (limits->HaveReachedMaxUploads() || + limits->HaveUploadedForHostname(hostname_)) { + return; + } + uint8 fingerprint[SHA1_LENGTH]; SECStatus rv = HASH_HashBuf( HASH_AlgSHA1, fingerprint, (uint8*) der_certs_[0].data(), @@ -104,6 +146,7 @@ class DnsCertProvenanceCheck : public NonThreadSafe { LOG(ERROR) << "FAILED" << " hostname:" << hostname_ << " domain:" << domain_; + Singleton<DnsCertLimits>::get()->DidUpload(hostname_); delegate_->OnDnsCertLookupFailed(hostname_, der_certs_); } else if (status == OK) { LOG(ERROR) << "GOOD" @@ -116,7 +159,6 @@ class DnsCertProvenanceCheck : public NonThreadSafe { delete this; } - const std::string hostname_; std::string domain_; DnsRRResolver* dnsrr_resolver_; diff --git a/net/socket/dns_cert_provenance_checker.h b/net/socket/dns_cert_provenance_checker.h index 8fef60f..810e272 100644 --- a/net/socket/dns_cert_provenance_checker.h +++ b/net/socket/dns_cert_provenance_checker.h @@ -27,6 +27,8 @@ class DnsCertProvenanceChecker { const std::vector<std::string>& der_certs) = 0; }; + virtual void Shutdown() = 0; + virtual ~DnsCertProvenanceChecker(); // DoAsyncVerification starts an asynchronous check for the given certificate diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 01f5984..66c0aa9 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h @@ -302,7 +302,7 @@ class URLRequest : public NonThreadSafe { // expected modification time is provided (non-zero), it will be used to // check if the underlying file has been changed or not. The granularity of // the time comparison is 1 second since time_t precision is used in WebKit. - void AppendBytesToUpload(const char* bytes, int bytes_len); + void AppendBytesToUpload(const char* bytes, int bytes_len); // takes a copy void AppendFileRangeToUpload(const FilePath& file_path, uint64 offset, uint64 length, const base::Time& expected_modification_time); @@ -431,9 +431,7 @@ class URLRequest : public NonThreadSafe { // and the response has not yet been called). bool is_pending() const { return is_pending_; } - // Returns the error status of the request. This value is 0 if there is no - // error. Otherwise, it is a value defined by the operating system (e.g., an - // error code returned by GetLastError() on windows). + // Returns the error status of the request. const URLRequestStatus& status() const { return status_; } // This method is called to start the request. The delegate will receive |