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

Side by Side Diff: net/http/http_network_transaction.cc

Issue 1378613004: Set Token-Binding HTTP header (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@tb-tls-ext-new
Patch Set: Add UMA logging of Token Binding support and NetLog event for Token Binding key lookup 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "net/http/http_network_transaction.h" 5 #include "net/http/http_network_transaction.h"
6 6
7 #include <set> 7 #include <set>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/base64.h"
10 #include "base/bind.h" 11 #include "base/bind.h"
11 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
12 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
13 #include "base/format_macros.h" 14 #include "base/format_macros.h"
14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
15 #include "base/metrics/field_trial.h" 16 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram_macros.h" 17 #include "base/metrics/histogram_macros.h"
17 #include "base/metrics/sparse_histogram.h" 18 #include "base/metrics/sparse_histogram.h"
18 #include "base/profiler/scoped_tracker.h" 19 #include "base/profiler/scoped_tracker.h"
19 #include "base/stl_util.h" 20 #include "base/stl_util.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 #include "net/socket/client_socket_factory.h" 54 #include "net/socket/client_socket_factory.h"
54 #include "net/socket/socks_client_socket_pool.h" 55 #include "net/socket/socks_client_socket_pool.h"
55 #include "net/socket/ssl_client_socket.h" 56 #include "net/socket/ssl_client_socket.h"
56 #include "net/socket/ssl_client_socket_pool.h" 57 #include "net/socket/ssl_client_socket_pool.h"
57 #include "net/socket/transport_client_socket_pool.h" 58 #include "net/socket/transport_client_socket_pool.h"
58 #include "net/spdy/spdy_http_stream.h" 59 #include "net/spdy/spdy_http_stream.h"
59 #include "net/spdy/spdy_session.h" 60 #include "net/spdy/spdy_session.h"
60 #include "net/spdy/spdy_session_pool.h" 61 #include "net/spdy/spdy_session_pool.h"
61 #include "net/ssl/ssl_cert_request_info.h" 62 #include "net/ssl/ssl_cert_request_info.h"
62 #include "net/ssl/ssl_connection_status_flags.h" 63 #include "net/ssl/ssl_connection_status_flags.h"
64 #include "net/ssl/token_binding.h"
63 #include "url/gurl.h" 65 #include "url/gurl.h"
64 #include "url/url_canon.h" 66 #include "url/url_canon.h"
65 67
66 namespace net { 68 namespace net {
67 69
68 namespace { 70 namespace {
69 71
70 void ProcessAlternativeServices(HttpNetworkSession* session, 72 void ProcessAlternativeServices(HttpNetworkSession* session,
71 const HttpResponseHeaders& headers, 73 const HttpResponseHeaders& headers,
72 const HostPortPair& http_host_port_pair) { 74 const HostPortPair& http_host_port_pair) {
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 proxy_ssl_config_.rev_checking_enabled = false; 193 proxy_ssl_config_.rev_checking_enabled = false;
192 } 194 }
193 195
194 if (request_->load_flags & LOAD_PREFETCH) 196 if (request_->load_flags & LOAD_PREFETCH)
195 response_.unused_since_prefetch = true; 197 response_.unused_since_prefetch = true;
196 198
197 // Channel ID is disabled if privacy mode is enabled for this request. 199 // Channel ID is disabled if privacy mode is enabled for this request.
198 if (request_->privacy_mode == PRIVACY_MODE_ENABLED) 200 if (request_->privacy_mode == PRIVACY_MODE_ENABLED)
199 server_ssl_config_.channel_id_enabled = false; 201 server_ssl_config_.channel_id_enabled = false;
200 202
203 if (session_->params().enable_token_binding &&
204 session_->params().channel_id_service) {
205 server_ssl_config_.token_binding_params.push_back(TB_PARAM_ECDSAP256);
206 }
207
201 next_state_ = STATE_NOTIFY_BEFORE_CREATE_STREAM; 208 next_state_ = STATE_NOTIFY_BEFORE_CREATE_STREAM;
202 int rv = DoLoop(OK); 209 int rv = DoLoop(OK);
203 if (rv == ERR_IO_PENDING) 210 if (rv == ERR_IO_PENDING)
204 callback_ = callback; 211 callback_ = callback;
205 return rv; 212 return rv;
206 } 213 }
207 214
208 int HttpNetworkTransaction::RestartIgnoringLastError( 215 int HttpNetworkTransaction::RestartIgnoringLastError(
209 const CompletionCallback& callback) { 216 const CompletionCallback& callback) {
210 DCHECK(!stream_.get()); 217 DCHECK(!stream_.get());
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 614
608 void HttpNetworkTransaction::GetConnectionAttempts( 615 void HttpNetworkTransaction::GetConnectionAttempts(
609 ConnectionAttempts* out) const { 616 ConnectionAttempts* out) const {
610 *out = connection_attempts_; 617 *out = connection_attempts_;
611 } 618 }
612 619
613 bool HttpNetworkTransaction::IsSecureRequest() const { 620 bool HttpNetworkTransaction::IsSecureRequest() const {
614 return request_->url.SchemeIsCryptographic(); 621 return request_->url.SchemeIsCryptographic();
615 } 622 }
616 623
624 bool HttpNetworkTransaction::IsTokenBindingEnabled() const {
625 if (!IsSecureRequest())
626 return false;
627 SSLInfo ssl_info;
628 stream_->GetSSLInfo(&ssl_info);
629 if (!ssl_info.token_binding_negotiated)
630 return false;
631 if (ssl_info.token_binding_key_param != TB_PARAM_ECDSAP256)
632 return false;
633 if (!session_->params().channel_id_service)
634 return false;
635 return true;
636 }
637
638 void HttpNetworkTransaction::RecordTokenBindingSupport() const {
639 enum {
640 DISABLED = 0,
641 CLIENT_ONLY = 1,
642 CLIENT_AND_SERVER = 2,
643 CLIENT_NO_CHANNEL_ID_SERVICE = 3,
644 UNSUPPORTED_KEY_PARAM = 4,
645 TOKEN_BINDING_SUPPORT_MAX
646 } supported;
647 if (!IsSecureRequest())
648 return;
649 SSLInfo ssl_info;
650 stream_->GetSSLInfo(&ssl_info);
651 if (!session_->params().enable_token_binding) {
652 supported = DISABLED;
653 } else if (!session_->params().channel_id_service) {
654 supported = CLIENT_NO_CHANNEL_ID_SERVICE;
655 } else if (ssl_info.token_binding_key_param != TB_PARAM_ECDSAP256) {
656 supported = UNSUPPORTED_KEY_PARAM;
davidben 2015/11/18 20:49:00 This can never happen, no? You'll only negotiate t
nharper 2015/12/04 01:42:19 My thought here was if the server can negotiate to
657 } else if (ssl_info.token_binding_negotiated) {
658 supported = CLIENT_AND_SERVER;
659 } else {
660 supported = CLIENT_ONLY;
661 }
662 UMA_HISTOGRAM_ENUMERATION("TokenBinding.Support", supported,
663 TOKEN_BINDING_SUPPORT_MAX);
664 }
665
617 bool HttpNetworkTransaction::UsingHttpProxyWithoutTunnel() const { 666 bool HttpNetworkTransaction::UsingHttpProxyWithoutTunnel() const {
618 return (proxy_info_.is_http() || proxy_info_.is_https() || 667 return (proxy_info_.is_http() || proxy_info_.is_https() ||
619 proxy_info_.is_quic()) && 668 proxy_info_.is_quic()) &&
620 !(request_->url.SchemeIs("https") || request_->url.SchemeIsWSOrWSS()); 669 !(request_->url.SchemeIs("https") || request_->url.SchemeIsWSOrWSS());
621 } 670 }
622 671
623 void HttpNetworkTransaction::DoCallback(int rv) { 672 void HttpNetworkTransaction::DoCallback(int rv) {
624 DCHECK_NE(rv, ERR_IO_PENDING); 673 DCHECK_NE(rv, ERR_IO_PENDING);
625 DCHECK(!callback_.is_null()); 674 DCHECK(!callback_.is_null());
626 675
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE: 718 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
670 rv = DoGenerateProxyAuthTokenComplete(rv); 719 rv = DoGenerateProxyAuthTokenComplete(rv);
671 break; 720 break;
672 case STATE_GENERATE_SERVER_AUTH_TOKEN: 721 case STATE_GENERATE_SERVER_AUTH_TOKEN:
673 DCHECK_EQ(OK, rv); 722 DCHECK_EQ(OK, rv);
674 rv = DoGenerateServerAuthToken(); 723 rv = DoGenerateServerAuthToken();
675 break; 724 break;
676 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE: 725 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
677 rv = DoGenerateServerAuthTokenComplete(rv); 726 rv = DoGenerateServerAuthTokenComplete(rv);
678 break; 727 break;
728 case STATE_GET_TOKEN_BINDING_KEY:
729 DCHECK_EQ(OK, rv);
730 rv = DoGetTokenBindingKey();
731 break;
732 case STATE_GET_TOKEN_BINDING_KEY_COMPLETE:
733 rv = DoGetTokenBindingKeyComplete(rv);
734 break;
679 case STATE_INIT_REQUEST_BODY: 735 case STATE_INIT_REQUEST_BODY:
680 DCHECK_EQ(OK, rv); 736 DCHECK_EQ(OK, rv);
681 rv = DoInitRequestBody(); 737 rv = DoInitRequestBody();
682 break; 738 break;
683 case STATE_INIT_REQUEST_BODY_COMPLETE: 739 case STATE_INIT_REQUEST_BODY_COMPLETE:
684 rv = DoInitRequestBodyComplete(rv); 740 rv = DoInitRequestBodyComplete(rv);
685 break; 741 break;
686 case STATE_BUILD_REQUEST: 742 case STATE_BUILD_REQUEST:
687 DCHECK_EQ(OK, rv); 743 DCHECK_EQ(OK, rv);
688 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST); 744 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 if (!ShouldApplyServerAuth()) 940 if (!ShouldApplyServerAuth())
885 return OK; 941 return OK;
886 return auth_controllers_[target]->MaybeGenerateAuthToken(request_, 942 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
887 io_callback_, 943 io_callback_,
888 net_log_); 944 net_log_);
889 } 945 }
890 946
891 int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) { 947 int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) {
892 DCHECK_NE(ERR_IO_PENDING, rv); 948 DCHECK_NE(ERR_IO_PENDING, rv);
893 if (rv == OK) 949 if (rv == OK)
894 next_state_ = STATE_INIT_REQUEST_BODY; 950 next_state_ = STATE_GET_TOKEN_BINDING_KEY;
895 return rv; 951 return rv;
896 } 952 }
897 953
954 int HttpNetworkTransaction::DoGetTokenBindingKey() {
955 next_state_ = STATE_GET_TOKEN_BINDING_KEY_COMPLETE;
956 if (!IsTokenBindingEnabled())
957 return OK;
958
959 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY);
960 ChannelIDService* channel_id_service = session_->params().channel_id_service;
961 return channel_id_service->GetOrCreateChannelID(
962 request_->url.host(), &token_binding_key_,
963 base::Bind(&HttpNetworkTransaction::OnIOComplete, base::Unretained(this)),
davidben 2015/11/18 20:49:00 io_callback_
nharper 2015/12/04 01:42:19 Done.
964 &token_binding_request_);
965 }
966
967 int HttpNetworkTransaction::DoGetTokenBindingKeyComplete(int rv) {
968 DCHECK_NE(ERR_IO_PENDING, rv);
969 next_state_ = STATE_INIT_REQUEST_BODY;
970 if (!IsTokenBindingEnabled())
971 return OK;
972
973 if (rv == OK && !token_binding_key_)
974 rv = ERR_CHANNEL_ID_IMPORT_FAILED;
davidben 2015/11/18 20:49:00 Is this possible?
nharper 2015/12/04 01:42:19 I can't see how this would be possible (GetOrCreat
975
976 net_log_.EndEventWithNetErrorCode(
977 NetLog::TYPE_HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY, rv);
978 return rv;
979 }
980
898 void HttpNetworkTransaction::BuildRequestHeaders( 981 void HttpNetworkTransaction::BuildRequestHeaders(
899 bool using_http_proxy_without_tunnel) { 982 bool using_http_proxy_without_tunnel) {
900 request_headers_.SetHeader(HttpRequestHeaders::kHost, 983 request_headers_.SetHeader(HttpRequestHeaders::kHost,
901 GetHostAndOptionalPort(request_->url)); 984 GetHostAndOptionalPort(request_->url));
902 985
903 // For compat with HTTP/1.0 servers and proxies: 986 // For compat with HTTP/1.0 servers and proxies:
904 if (using_http_proxy_without_tunnel) { 987 if (using_http_proxy_without_tunnel) {
905 request_headers_.SetHeader(HttpRequestHeaders::kProxyConnection, 988 request_headers_.SetHeader(HttpRequestHeaders::kProxyConnection,
906 "keep-alive"); 989 "keep-alive");
907 } else { 990 } else {
(...skipping 13 matching lines...) Expand all
921 } else if (request_->method == "POST" || request_->method == "PUT") { 1004 } else if (request_->method == "POST" || request_->method == "PUT") {
922 // An empty POST/PUT request still needs a content length. As for HEAD, 1005 // An empty POST/PUT request still needs a content length. As for HEAD,
923 // IE and Safari also add a content length header. Presumably it is to 1006 // IE and Safari also add a content length header. Presumably it is to
924 // support sending a HEAD request to an URL that only expects to be sent a 1007 // support sending a HEAD request to an URL that only expects to be sent a
925 // POST or some other method that normally would have a message body. 1008 // POST or some other method that normally would have a message body.
926 // Firefox (40.0) does not send the header, and RFC 7230 & 7231 1009 // Firefox (40.0) does not send the header, and RFC 7230 & 7231
927 // specify that it should not be sent due to undefined behavior. 1010 // specify that it should not be sent due to undefined behavior.
928 request_headers_.SetHeader(HttpRequestHeaders::kContentLength, "0"); 1011 request_headers_.SetHeader(HttpRequestHeaders::kContentLength, "0");
929 } 1012 }
930 1013
1014 RecordTokenBindingSupport();
1015 if (token_binding_key_) {
davidben 2015/11/18 20:49:00 An HttpNetworkSession may run through a request mu
nharper 2015/12/04 01:42:19 Done.
1016 std::string token_binding_header = BuildTokenBindingHeader();
1017 if (token_binding_header != "") {
1018 request_headers_.SetHeader(HttpRequestHeaders::kTokenBinding,
1019 token_binding_header);
1020 }
1021 }
1022
931 // Honor load flags that impact proxy caches. 1023 // Honor load flags that impact proxy caches.
932 if (request_->load_flags & LOAD_BYPASS_CACHE) { 1024 if (request_->load_flags & LOAD_BYPASS_CACHE) {
933 request_headers_.SetHeader(HttpRequestHeaders::kPragma, "no-cache"); 1025 request_headers_.SetHeader(HttpRequestHeaders::kPragma, "no-cache");
934 request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "no-cache"); 1026 request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
935 } else if (request_->load_flags & LOAD_VALIDATE_CACHE) { 1027 } else if (request_->load_flags & LOAD_VALIDATE_CACHE) {
936 request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0"); 1028 request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
937 } 1029 }
938 1030
939 if (ShouldApplyProxyAuth() && HaveAuth(HttpAuth::AUTH_PROXY)) 1031 if (ShouldApplyProxyAuth() && HaveAuth(HttpAuth::AUTH_PROXY))
940 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader( 1032 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader(
941 &request_headers_); 1033 &request_headers_);
942 if (ShouldApplyServerAuth() && HaveAuth(HttpAuth::AUTH_SERVER)) 1034 if (ShouldApplyServerAuth() && HaveAuth(HttpAuth::AUTH_SERVER))
943 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader( 1035 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader(
944 &request_headers_); 1036 &request_headers_);
945 1037
946 request_headers_.MergeFrom(request_->extra_headers); 1038 request_headers_.MergeFrom(request_->extra_headers);
947 1039
948 if (using_http_proxy_without_tunnel && 1040 if (using_http_proxy_without_tunnel &&
949 !before_proxy_headers_sent_callback_.is_null()) 1041 !before_proxy_headers_sent_callback_.is_null())
950 before_proxy_headers_sent_callback_.Run(proxy_info_, &request_headers_); 1042 before_proxy_headers_sent_callback_.Run(proxy_info_, &request_headers_);
951 1043
952 response_.did_use_http_auth = 1044 response_.did_use_http_auth =
953 request_headers_.HasHeader(HttpRequestHeaders::kAuthorization) || 1045 request_headers_.HasHeader(HttpRequestHeaders::kAuthorization) ||
954 request_headers_.HasHeader(HttpRequestHeaders::kProxyAuthorization); 1046 request_headers_.HasHeader(HttpRequestHeaders::kProxyAuthorization);
955 } 1047 }
956 1048
1049 std::string HttpNetworkTransaction::BuildTokenBindingHeader() {
1050 std::string provided_token_binding;
1051 int rv = stream_->GetProvidedTokenBindingWithKey(token_binding_key_,
1052 &provided_token_binding);
1053 if (rv != OK)
1054 return "";
davidben 2015/11/18 20:49:00 If this or below fails, it should probably be fata
nharper 2015/12/04 01:42:19 Done.
1055 std::vector<std::string> token_bindings;
1056 token_bindings.push_back(provided_token_binding);
1057 std::string header;
1058 rv = BuildTokenBindingMessageFromTokenBindings(token_bindings, &header);
1059 if (rv != OK)
1060 return "";
1061 std::string base64_header;
1062 base::Base64Encode(header, &base64_header);
1063 base::ReplaceChars(base64_header, "+", "-", &base64_header);
1064 base::ReplaceChars(base64_header, "/", "_", &base64_header);
davidben 2015/11/18 20:49:00 base/base64url.h
nharper 2015/12/04 01:42:19 Done.
1065 return base64_header;
1066 }
1067
957 int HttpNetworkTransaction::DoInitRequestBody() { 1068 int HttpNetworkTransaction::DoInitRequestBody() {
958 next_state_ = STATE_INIT_REQUEST_BODY_COMPLETE; 1069 next_state_ = STATE_INIT_REQUEST_BODY_COMPLETE;
959 int rv = OK; 1070 int rv = OK;
960 if (request_->upload_data_stream) 1071 if (request_->upload_data_stream)
961 rv = request_->upload_data_stream->Init(io_callback_); 1072 rv = request_->upload_data_stream->Init(io_callback_);
962 return rv; 1073 return rv;
963 } 1074 }
964 1075
965 int HttpNetworkTransaction::DoInitRequestBodyComplete(int result) { 1076 int HttpNetworkTransaction::DoInitRequestBodyComplete(int result) {
966 if (result == OK) 1077 if (result == OK)
(...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after
1673 DCHECK(stream_request_); 1784 DCHECK(stream_request_);
1674 1785
1675 // Since the transaction can restart with auth credentials, it may create a 1786 // Since the transaction can restart with auth credentials, it may create a
1676 // stream more than once. Accumulate all of the connection attempts across 1787 // stream more than once. Accumulate all of the connection attempts across
1677 // those streams by appending them to the vector: 1788 // those streams by appending them to the vector:
1678 for (const auto& attempt : stream_request_->connection_attempts()) 1789 for (const auto& attempt : stream_request_->connection_attempts())
1679 connection_attempts_.push_back(attempt); 1790 connection_attempts_.push_back(attempt);
1680 } 1791 }
1681 1792
1682 } // namespace net 1793 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698