Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Side by Side Diff: chrome/browser/local_discovery/privet_http_impl.cc

Issue 1417363004: Verify certificate of Privet v3 device (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698