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.h b/system-proxy/proxy_connect_job.h
index b872c1c..004093c 100644
--- a/system-proxy/proxy_connect_job.h
+++ b/system-proxy/proxy_connect_job.h
@@ -71,6 +71,7 @@
 
   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);
@@ -83,6 +84,12 @@
   virtual bool Start();
   void OnProxyResolution(const std::list<std::string>& proxy_servers);
 
+  // Enables storing curl debug information for test.
+  void StoreRequestHeadersForTesting();
+  // Returns the HTTP headers sent by the curl client. Tests must call
+  // `StoreRequestHeadersForTesting` before calling this method.
+  std::string GetRequestHeadersForTesting();
+
   friend std::ostream& operator<<(std::ostream& stream,
                                   const ProxyConnectJob& job);
 
@@ -104,6 +111,8 @@
   FRIEND_TEST(HttpServerProxyConnectJobTest, MultipleReadConnectRequest);
   FRIEND_TEST(HttpServerProxyConnectJobTest, BufferedClientData);
   FRIEND_TEST(HttpServerProxyConnectJobTest, BufferedClientDataAltEnding);
+  FRIEND_TEST(HttpServerProxyConnectJobTest, PolicyAuthSchemeOk);
+  FRIEND_TEST(HttpServerProxyConnectJobTest, PolicyAuthBadScheme);
 
   // Called when the client socket is ready for reading.
   void OnClientReadReady();
@@ -150,6 +159,9 @@
   bool authentication_timer_started_ = false;
 
   std::string credentials_;
+  // Bitmask to tell curl which authentication methods are allowed to be used
+  // with `credentials_`. This value is set with the `CURLOPT_PROXYAUTH` option.
+  int64_t curl_auth_schemes_;
   // CONNECT request and playload data read from the client socket. The client
   // may send the HTTP CONNECT request across multiple socket writes.
   // |connect_data_| will cache the partial messages until we receive the end of
@@ -169,6 +181,9 @@
   // required).
   base::CancelableClosure credentials_request_timeout_callback_;
 
+  bool store_headers_for_testing_ = false;
+  std::string request_headers_for_testing_;
+
   std::unique_ptr<patchpanel::Socket> client_socket_;
   std::unique_ptr<base::FileDescriptorWatcher::Controller> read_watcher_;
   base::WeakPtrFactory<ProxyConnectJob> weak_ptr_factory_{this};