system-proxy: Secure system credentials
Currently System-proxy sends the policy set credentials with every
connect request to a remote proxy. Since less secure authentication
schemes send the credentials in clear to the proxy, an attacker can
easily obtain the policy set credentials.
To protect against a downgrade attack, this CL restricts the auth
schemes for which the policy set credentials can be applied.
BUG=chromium:1132247
TEST=HttpServerProxyConnectJobTest.PolicyAuth*
Change-Id: I17e2d3e38b1560f0fadf347657bd3f4b6e1bae09
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2483831
Tested-by: Andreea-Elena Costinas <acostinas@google.com>
Commit-Queue: Andreea-Elena Costinas <acostinas@google.com>
Reviewed-by: Pavol Marko <pmarko@chromium.org>
diff --git a/system-proxy/proxy_connect_job.cc b/system-proxy/proxy_connect_job.cc
index c2ba1bc..ee228b8 100644
--- a/system-proxy/proxy_connect_job.cc
+++ b/system-proxy/proxy_connect_job.cc
@@ -109,13 +109,30 @@
return size * nmemb;
}
+// This callback receives debug information from curl, as specified in the
+// `type` argument (e.g. incoming or outgoing HTTP headers, SSL data).
+static size_t WriteDebugInfoCallback(CURL* handle,
+ curl_infotype type,
+ char* contents,
+ size_t size,
+ void* userdata) {
+ // We're only interested in outgoing headers for testing.
+ if (type != CURLINFO_HEADER_OUT)
+ return 0;
+ std::string* headers = (std::string*)userdata;
+ *headers = std::string(contents, size);
+ return 0;
+}
+
ProxyConnectJob::ProxyConnectJob(
std::unique_ptr<patchpanel::Socket> socket,
const std::string& credentials,
+ int64_t curl_auth_schemes,
ResolveProxyCallback resolve_proxy_callback,
AuthenticationRequiredCallback auth_required_callback,
OnConnectionSetupFinishedCallback setup_finished_callback)
: credentials_(credentials),
+ curl_auth_schemes_(curl_auth_schemes),
resolve_proxy_callback_(std::move(resolve_proxy_callback)),
auth_required_callback_(std::move(auth_required_callback)),
setup_finished_callback_(std::move(setup_finished_callback)),
@@ -147,6 +164,13 @@
return true;
}
+void ProxyConnectJob::StoreRequestHeadersForTesting() {
+ store_headers_for_testing_ = true;
+}
+std::string ProxyConnectJob::GetRequestHeadersForTesting() {
+ return request_headers_for_testing_;
+}
+
void ProxyConnectJob::OnClientReadReady() {
// The first message should be a HTTP CONNECT request.
std::vector<char> buf(kMaxHttpRequestHeadersSize);
@@ -242,6 +266,9 @@
return;
}
credentials_ = credentials;
+ // Covers the case for which `curl_auth_schemes_` was initialized with policy
+ // set schemes which are not supported by the remote remote server.
+ curl_auth_schemes_ = CURLAUTH_ANY;
VLOG(1) << "Connecting to the remote server with provided credentials";
DoCurlServerConnection();
}
@@ -287,7 +314,7 @@
curl_easy_setopt(easyhandle, CURLOPT_CONNECT_ONLY, 1);
// Allow libcurl to pick authentication method. Curl will use the most
// secure one the remote site claims to support.
- curl_easy_setopt(easyhandle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+ curl_easy_setopt(easyhandle, CURLOPT_PROXYAUTH, curl_auth_schemes_);
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, credentials_.c_str());
}
curl_easy_setopt(easyhandle, CURLOPT_CONNECTTIMEOUT_MS,
@@ -296,7 +323,13 @@
curl_easy_setopt(easyhandle, CURLOPT_HEADERDATA, &http_response_headers);
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &http_response_body);
-
+ if (store_headers_for_testing_) {
+ curl_easy_setopt(easyhandle, CURLOPT_DEBUGFUNCTION, WriteDebugInfoCallback);
+ curl_easy_setopt(easyhandle, CURLOPT_DEBUGDATA,
+ &request_headers_for_testing_);
+ // The DEBUGFUNCTION has no effect until we enable VERBOSE.
+ curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1L);
+ }
res = curl_easy_perform(easyhandle);
curl_easy_getinfo(easyhandle, CURLINFO_HTTP_CONNECTCODE,
&http_response_code_);