Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/local_discovery/privet_http_impl.h" | 5 #include "chrome/browser/local_discovery/privet_http_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
| 13 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
| 14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "base/thread_task_runner_handle.h" | 16 #include "base/thread_task_runner_handle.h" |
| 17 #include "chrome/browser/local_discovery/privet_constants.h" | 17 #include "chrome/browser/local_discovery/privet_constants.h" |
| 18 #include "chrome/common/chrome_content_client.h" | |
| 18 #include "chrome/common/cloud_print/cloud_print_constants.h" | 19 #include "chrome/common/cloud_print/cloud_print_constants.h" |
| 19 #include "net/base/url_util.h" | 20 #include "net/base/url_util.h" |
| 21 #include "net/cert/cert_verifier.h" | |
| 22 #include "net/cert/cert_verify_result.h" | |
| 23 #include "net/url_request/url_request_context.h" | |
| 24 #include "net/url_request/url_request_context_builder.h" | |
| 20 #include "url/gurl.h" | 25 #include "url/gurl.h" |
| 21 | 26 |
| 22 #if defined(ENABLE_PRINT_PREVIEW) | 27 #if defined(ENABLE_PRINT_PREVIEW) |
| 23 #include "chrome/browser/local_discovery/pwg_raster_converter.h" | 28 #include "chrome/browser/local_discovery/pwg_raster_converter.h" |
| 24 #include "components/cloud_devices/common/printer_description.h" | 29 #include "components/cloud_devices/common/printer_description.h" |
| 25 #include "printing/pdf_render_settings.h" | 30 #include "printing/pdf_render_settings.h" |
| 26 #include "printing/pwg_raster_settings.h" | 31 #include "printing/pwg_raster_settings.h" |
| 27 #include "ui/gfx/text_elider.h" | 32 #include "ui/gfx/text_elider.h" |
| 28 #endif // ENABLE_PRINT_PREVIEW | 33 #endif // ENABLE_PRINT_PREVIEW |
| 29 | 34 |
| 30 namespace local_discovery { | 35 namespace local_discovery { |
| 31 | 36 |
| 32 namespace { | 37 namespace { |
| 38 | |
| 33 const char kUrlPlaceHolder[] = "http://host/"; | 39 const char kUrlPlaceHolder[] = "http://host/"; |
| 34 const char kPrivetRegisterActionArgName[] = "action"; | 40 const char kPrivetRegisterActionArgName[] = "action"; |
| 35 const char kPrivetRegisterUserArgName[] = "user"; | 41 const char kPrivetRegisterUserArgName[] = "user"; |
| 36 | 42 |
| 37 const int kPrivetCancelationTimeoutSeconds = 3; | 43 const int kPrivetCancelationTimeoutSeconds = 3; |
| 38 | 44 |
| 39 #if defined(ENABLE_PRINT_PREVIEW) | 45 #if defined(ENABLE_PRINT_PREVIEW) |
| 40 const char kPrivetURLKeyUserName[] = "user_name"; | 46 const char kPrivetURLKeyUserName[] = "user_name"; |
| 41 const char kPrivetURLKeyClientName[] = "client_name"; | 47 const char kPrivetURLKeyClientName[] = "client_name"; |
| 42 const char kPrivetURLKeyJobname[] = "job_name"; | 48 const char kPrivetURLKeyJobname[] = "job_name"; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 const std::string& query_params) { | 80 const std::string& query_params) { |
| 75 GURL url(kUrlPlaceHolder); | 81 GURL url(kUrlPlaceHolder); |
| 76 GURL::Replacements replacements; | 82 GURL::Replacements replacements; |
| 77 replacements.SetPathStr(path); | 83 replacements.SetPathStr(path); |
| 78 if (!query_params.empty()) { | 84 if (!query_params.empty()) { |
| 79 replacements.SetQueryStr(query_params); | 85 replacements.SetQueryStr(query_params); |
| 80 } | 86 } |
| 81 return url.ReplaceComponents(replacements); | 87 return url.ReplaceComponents(replacements); |
| 82 } | 88 } |
| 83 | 89 |
| 90 // Used before we have any certificate fingerprint. | |
| 91 class FailingCertVerifier : public net::CertVerifier { | |
| 92 public: | |
| 93 int Verify(net::X509Certificate* cert, | |
| 94 const std::string& hostname, | |
| 95 const std::string& ocsp_response, | |
| 96 int flags, | |
| 97 net::CRLSet* crl_set, | |
| 98 net::CertVerifyResult* verify_result, | |
| 99 const net::CompletionCallback& callback, | |
| 100 scoped_ptr<Request>* out_req, | |
| 101 const net::BoundNetLog& net_log) override { | |
| 102 verify_result->verified_cert = cert; | |
|
Ryan Sleevi
2015/10/28 22:52:15
BUG: You fail to reset the verify_result, causing
Vitaly Buka (NO REVIEWS)
2015/10/29 00:19:10
Done.
Vitaly Buka (NO REVIEWS)
2015/10/29 00:19:10
That one was copied from ssl_hmac_channel_authenti
| |
| 103 verify_result->cert_status = net::CERT_STATUS_INVALID; | |
| 104 return net::ERR_CERT_INVALID; | |
| 105 } | |
| 106 }; | |
| 107 | |
| 108 // Used before when we have the certificate fingerprint. | |
| 109 // Privet v3 devices should supports https but with self-signed sertificates. | |
|
Ryan Sleevi
2015/10/28 22:52:15
TYPO: certificates
Vitaly Buka (NO REVIEWS)
2015/10/29 00:19:10
Done.
| |
| 110 // So normal validation is not usefull. | |
| 111 // Before using https Privet v3 pairing generates same secret on device and | |
| 112 // client side Spake2 on insecure channel. Than device sends fingerprint | |
|
Ryan Sleevi
2015/10/28 22:52:15
typo: SPAKE2
// Before using HTTPS, Privet v3 pai
Vitaly Buka (NO REVIEWS)
2015/10/29 00:19:10
Done.
| |
| 113 // to client using same insecure channel. fingerprint is signed with the secret | |
| 114 // generated before. | |
| 115 // More info on pairing: | |
| 116 // https://developers.google.com/cloud-devices/v1/reference/local-api/pairing_st art | |
| 117 class FingerprintVerifier : public net::CertVerifier { | |
|
Ryan Sleevi
2015/10/28 22:52:15
Your class documentation doesn't explain at all wh
Vitaly Buka (NO REVIEWS)
2015/10/29 00:19:10
Moved large part of comment to SwitchToHttps to ke
| |
| 118 public: | |
| 119 explicit FingerprintVerifier( | |
| 120 const net::SHA256HashValue& certificate_fingerprint) | |
| 121 : certificate_fingerprint_(certificate_fingerprint) {} | |
| 122 | |
| 123 int Verify(net::X509Certificate* cert, | |
| 124 const std::string& hostname, | |
| 125 const std::string& ocsp_response, | |
| 126 int flags, | |
| 127 net::CRLSet* crl_set, | |
| 128 net::CertVerifyResult* verify_result, | |
| 129 const net::CompletionCallback& callback, | |
| 130 scoped_ptr<Request>* out_req, | |
| 131 const net::BoundNetLog& net_log) override { | |
| 132 // Mark certificat as invalid as we didn't check that. | |
| 133 verify_result->verified_cert = cert; | |
| 134 verify_result->cert_status = net::CERT_STATUS_INVALID; | |
| 135 | |
| 136 auto fingerprint = | |
| 137 net::X509Certificate::CalculateFingerprint256(cert->os_cert_handle()); | |
| 138 | |
| 139 return certificate_fingerprint_.Equals(fingerprint) ? net::OK | |
| 140 : net::ERR_CERT_INVALID; | |
| 141 } | |
| 142 | |
| 143 private: | |
| 144 net::SHA256HashValue certificate_fingerprint_; | |
| 145 | |
| 146 DISALLOW_COPY_AND_ASSIGN(FingerprintVerifier); | |
| 147 }; | |
| 148 | |
| 149 class PrivetContextGetter : public net::URLRequestContextGetter { | |
| 150 public: | |
| 151 PrivetContextGetter( | |
| 152 const scoped_refptr<base::SingleThreadTaskRunner>& net_task_runner, | |
| 153 const net::SHA256HashValue& certificate_fingerprint) | |
| 154 : verifier_(new FingerprintVerifier(certificate_fingerprint)), | |
| 155 net_task_runner_(net_task_runner) {} | |
| 156 | |
| 157 // Don't allow any https without fingerprint. Device with valid certificate | |
| 158 // may be different from the one which user is trying to pair. | |
| 159 explicit PrivetContextGetter( | |
| 160 const scoped_refptr<base::SingleThreadTaskRunner>& net_task_runner) | |
| 161 : verifier_(new FailingCertVerifier()), | |
| 162 net_task_runner_(net_task_runner) {} | |
| 163 | |
| 164 net::URLRequestContext* GetURLRequestContext() override { | |
| 165 if (!context_) { | |
| 166 net::URLRequestContextBuilder builder; | |
| 167 builder.set_proxy_service(net::ProxyService::CreateDirect()); | |
| 168 builder.SetSpdyAndQuicEnabled(false, false); | |
| 169 builder.DisableHttpCache(); | |
| 170 builder.SetCertVerifier(verifier_.Pass()); | |
| 171 builder.set_user_agent(::GetUserAgent()); | |
| 172 context_ = builder.Build(); | |
| 173 } | |
| 174 return context_.get(); | |
|
Ryan Sleevi
2015/10/28 22:52:15
This is all VERY surprising; creating new URL requ
Vitaly Buka (NO REVIEWS)
2015/10/29 00:19:10
I create one context per context getter and two co
| |
| 175 } | |
| 176 | |
| 177 scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() | |
| 178 const override { | |
| 179 return net_task_runner_; | |
| 180 } | |
| 181 | |
| 182 protected: | |
| 183 ~PrivetContextGetter() override = default; | |
| 184 | |
| 185 private: | |
| 186 scoped_ptr<net::CertVerifier> verifier_; | |
| 187 scoped_ptr<net::URLRequestContext> context_; | |
| 188 scoped_refptr<base::SingleThreadTaskRunner> net_task_runner_; | |
| 189 | |
| 190 DISALLOW_COPY_AND_ASSIGN(PrivetContextGetter); | |
| 191 }; | |
| 192 | |
| 84 } // namespace | 193 } // namespace |
| 85 | 194 |
| 86 PrivetInfoOperationImpl::PrivetInfoOperationImpl( | 195 PrivetInfoOperationImpl::PrivetInfoOperationImpl( |
| 87 PrivetHTTPClient* privet_client, | 196 PrivetHTTPClient* privet_client, |
| 88 const PrivetJSONOperation::ResultCallback& callback) | 197 const PrivetJSONOperation::ResultCallback& callback) |
| 89 : privet_client_(privet_client), callback_(callback) { | 198 : privet_client_(privet_client), callback_(callback) { |
| 90 } | 199 } |
| 91 | 200 |
| 92 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() { | 201 PrivetInfoOperationImpl::~PrivetInfoOperationImpl() { |
| 93 } | 202 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 int visible_http_code = -1; | 281 int visible_http_code = -1; |
| 173 FailureReason reason = FAILURE_NETWORK; | 282 FailureReason reason = FAILURE_NETWORK; |
| 174 | 283 |
| 175 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) { | 284 if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) { |
| 176 visible_http_code = fetcher->response_code(); | 285 visible_http_code = fetcher->response_code(); |
| 177 reason = FAILURE_HTTP_ERROR; | 286 reason = FAILURE_HTTP_ERROR; |
| 178 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) { | 287 } else if (error == PrivetURLFetcher::JSON_PARSE_ERROR) { |
| 179 reason = FAILURE_MALFORMED_RESPONSE; | 288 reason = FAILURE_MALFORMED_RESPONSE; |
| 180 } else if (error == PrivetURLFetcher::TOKEN_ERROR) { | 289 } else if (error == PrivetURLFetcher::TOKEN_ERROR) { |
| 181 reason = FAILURE_TOKEN; | 290 reason = FAILURE_TOKEN; |
| 182 } else if (error == PrivetURLFetcher::RETRY_ERROR) { | 291 } else if (error == PrivetURLFetcher::UNKNOWN_ERROR) { |
| 183 reason = FAILURE_RETRY; | 292 reason = FAILURE_UNKNOWN; |
| 184 } | 293 } |
| 185 | 294 |
| 186 delegate_->OnPrivetRegisterError(this, | 295 delegate_->OnPrivetRegisterError(this, |
| 187 current_action_, | 296 current_action_, |
| 188 reason, | 297 reason, |
| 189 visible_http_code, | 298 visible_http_code, |
| 190 NULL); | 299 NULL); |
| 191 } | 300 } |
| 192 | 301 |
| 193 void PrivetRegisterOperationImpl::OnParsedJson( | 302 void PrivetRegisterOperationImpl::OnParsedJson( |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 684 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( | 793 void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( |
| 685 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { | 794 scoped_ptr<PWGRasterConverter> pwg_raster_converter) { |
| 686 pwg_raster_converter_ = pwg_raster_converter.Pass(); | 795 pwg_raster_converter_ = pwg_raster_converter.Pass(); |
| 687 } | 796 } |
| 688 #endif // ENABLE_PRINT_PREVIEW | 797 #endif // ENABLE_PRINT_PREVIEW |
| 689 | 798 |
| 690 PrivetHTTPClientImpl::PrivetHTTPClientImpl( | 799 PrivetHTTPClientImpl::PrivetHTTPClientImpl( |
| 691 const std::string& name, | 800 const std::string& name, |
| 692 const net::HostPortPair& host_port, | 801 const net::HostPortPair& host_port, |
| 693 net::URLRequestContextGetter* request_context) | 802 net::URLRequestContextGetter* request_context) |
| 694 : name_(name), request_context_(request_context), host_port_(host_port) {} | 803 : PrivetHTTPClientImpl(name, |
| 804 host_port, | |
| 805 request_context->GetNetworkTaskRunner()) {} | |
| 806 | |
| 807 PrivetHTTPClientImpl::PrivetHTTPClientImpl( | |
| 808 const std::string& name, | |
| 809 const net::HostPortPair& host_port, | |
| 810 const scoped_refptr<base::SingleThreadTaskRunner>& net_task_runner) | |
| 811 : name_(name), | |
| 812 context_getter_(new PrivetContextGetter(net_task_runner)), | |
| 813 host_port_(host_port) {} | |
| 695 | 814 |
| 696 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { | 815 PrivetHTTPClientImpl::~PrivetHTTPClientImpl() { |
| 697 } | 816 } |
| 698 | 817 |
| 699 const std::string& PrivetHTTPClientImpl::GetName() { | 818 const std::string& PrivetHTTPClientImpl::GetName() { |
| 700 return name_; | 819 return name_; |
| 701 } | 820 } |
| 702 | 821 |
| 703 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation( | 822 scoped_ptr<PrivetJSONOperation> PrivetHTTPClientImpl::CreateInfoOperation( |
| 704 const PrivetJSONOperation::ResultCallback& callback) { | 823 const PrivetJSONOperation::ResultCallback& callback) { |
| 705 return scoped_ptr<PrivetJSONOperation>( | 824 return scoped_ptr<PrivetJSONOperation>( |
| 706 new PrivetInfoOperationImpl(this, callback)); | 825 new PrivetInfoOperationImpl(this, callback)); |
| 707 } | 826 } |
| 708 | 827 |
| 709 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher( | 828 scoped_ptr<PrivetURLFetcher> PrivetHTTPClientImpl::CreateURLFetcher( |
| 710 const GURL& url, | 829 const GURL& url, |
| 711 net::URLFetcher::RequestType request_type, | 830 net::URLFetcher::RequestType request_type, |
| 712 PrivetURLFetcher::Delegate* delegate) { | 831 PrivetURLFetcher::Delegate* delegate) { |
| 713 GURL::Replacements replacements; | 832 GURL::Replacements replacements; |
| 714 replacements.SetHostStr(host_port_.host()); | 833 replacements.SetHostStr(host_port_.host()); |
| 715 std::string port( | 834 std::string port = base::UintToString(host_port_.port()); |
| 716 base::UintToString(host_port_.port())); // Keep string alive. | |
| 717 replacements.SetPortStr(port); | 835 replacements.SetPortStr(port); |
| 836 std::string scheme = IsInHttpsMode() ? "https" : "http"; | |
| 837 replacements.SetSchemeStr(scheme); | |
| 718 return scoped_ptr<PrivetURLFetcher>( | 838 return scoped_ptr<PrivetURLFetcher>( |
| 719 new PrivetURLFetcher(url.ReplaceComponents(replacements), | 839 new PrivetURLFetcher(url.ReplaceComponents(replacements), request_type, |
| 720 request_type, | 840 context_getter_, delegate)); |
| 721 request_context_.get(), | |
| 722 delegate)); | |
| 723 } | 841 } |
| 724 | 842 |
| 725 void PrivetHTTPClientImpl::RefreshPrivetToken( | 843 void PrivetHTTPClientImpl::RefreshPrivetToken( |
| 726 const PrivetURLFetcher::TokenCallback& callback) { | 844 const PrivetURLFetcher::TokenCallback& callback) { |
| 727 token_callbacks_.push_back(callback); | 845 token_callbacks_.push_back(callback); |
| 728 | 846 |
| 729 if (!info_operation_) { | 847 if (!info_operation_) { |
| 730 info_operation_ = CreateInfoOperation( | 848 info_operation_ = CreateInfoOperation( |
| 731 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone, | 849 base::Bind(&PrivetHTTPClientImpl::OnPrivetInfoDone, |
| 732 base::Unretained(this))); | 850 base::Unretained(this))); |
| 733 info_operation_->Start(); | 851 info_operation_->Start(); |
| 734 } | 852 } |
| 735 } | 853 } |
| 736 | 854 |
| 855 void PrivetHTTPClientImpl::SwitchToHttps( | |
| 856 uint16_t port, | |
| 857 const net::SHA256HashValue& certificate_fingerprint) { | |
| 858 use_https_ = true; | |
| 859 host_port_.set_port(port); | |
| 860 context_getter_ = new PrivetContextGetter( | |
| 861 context_getter_->GetNetworkTaskRunner(), certificate_fingerprint); | |
|
Ryan Sleevi
2015/10/28 22:52:15
I'm fairly certain this is all sorts of wrong re:
Vitaly Buka (NO REVIEWS)
2015/10/29 00:19:10
Did you mean performance? Two getters per device?
| |
| 862 } | |
| 863 | |
| 864 bool PrivetHTTPClientImpl::IsInHttpsMode() const { | |
| 865 return use_https_; | |
| 866 } | |
| 867 | |
| 737 void PrivetHTTPClientImpl::OnPrivetInfoDone( | 868 void PrivetHTTPClientImpl::OnPrivetInfoDone( |
| 738 const base::DictionaryValue* value) { | 869 const base::DictionaryValue* value) { |
| 739 info_operation_.reset(); | 870 info_operation_.reset(); |
| 740 std::string token; | 871 std::string token; |
| 741 | 872 |
| 742 // If this does not succeed, token will be empty, and an empty string | 873 // If this does not succeed, token will be empty, and an empty string |
| 743 // is our sentinel value, since empty X-Privet-Tokens are not allowed. | 874 // is our sentinel value, since empty X-Privet-Tokens are not allowed. |
| 744 if (value) { | 875 if (value) { |
| 745 value->GetString(kPrivetInfoKeyToken, &token); | 876 value->GetString(kPrivetInfoKeyToken, &token); |
| 746 } | 877 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 791 PrivetLocalPrintOperation::Delegate* delegate) { | 922 PrivetLocalPrintOperation::Delegate* delegate) { |
| 792 #if defined(ENABLE_PRINT_PREVIEW) | 923 #if defined(ENABLE_PRINT_PREVIEW) |
| 793 return scoped_ptr<PrivetLocalPrintOperation>( | 924 return scoped_ptr<PrivetLocalPrintOperation>( |
| 794 new PrivetLocalPrintOperationImpl(info_client(), delegate)); | 925 new PrivetLocalPrintOperationImpl(info_client(), delegate)); |
| 795 #else | 926 #else |
| 796 return scoped_ptr<PrivetLocalPrintOperation>(); | 927 return scoped_ptr<PrivetLocalPrintOperation>(); |
| 797 #endif // ENABLE_PRINT_PREVIEW | 928 #endif // ENABLE_PRINT_PREVIEW |
| 798 } | 929 } |
| 799 | 930 |
| 800 } // namespace local_discovery | 931 } // namespace local_discovery |
| OLD | NEW |