Add SSL support for http_client (EventService)

This commit adds the initial SSL support for http_client which can be
used for sending asynchronous Events/MetricReports to subscribed Event
Listener servers over secure channel.

Current implementation of http client only works for http protocol.
With current implementation, http client can be configured to work
with secure http (HTTPS). As part of implementation it adds the SSL
handshake mechanism and enforces the peer ceritificate verification.

The http-client uses the cipher suites which are supported by mozilla
browser and as recommended by OWASP. For better security enforcement
its disables the SSLv2, SSLv3, TLSv1, TLSv1.1 as described in below
OWASP cheetsheet.

It is validated with RootCA certificate(PEM) for now. Adding support
for different certificates can be looked in future as need arises.

[1]: https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html

Tested:
 - Created new subscription with SSL destination(https) and confirmed
   that events are seen on EventListener side.
   URI: /redfish/v1/EventService/Subscriptions
   Method: POST
   Body:
   {
     "Context": "CustomText",
     "Destination": "https://<IP>:4000/service/collector/event_logs",
     "EventFormatType": "Event",
     "DeliveryRetryPolicy": "RetryForever",
     "Protocol": "Redfish"
   }

 - Unit tested the non-SSL connection by disabling the check in code
   (Note: EventService blocks all Non-SSL destinations). Verified that
   all events are properly shown on EventListener.
   URI: /redfish/v1/EventService/Subscriptions
   Method: POST
   Body:
   {
     "Context": "CustomText",
     "Destination": "http://<IP>:4001/service/collector/event_logs",
     "EventFormatType": "Event",
     "Protocol": "Redfish"
   }

 - Combined above two tests and verified both SSL & Non-SSL work fine in
   congention.

 - Created subscription with different URI paths on same IP, Port and
   protocol and verified that events sent as expected.

Change-Id: I13b2fc942c9ce6c55cd7348aae1e088a3f3d7fd9
Signed-off-by: AppaRao Puli <apparao.puli@intel.com>
Signed-off-by: Ed Tanous <edtanous@google.com>
diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp
index 431dd84..c6ceb83 100644
--- a/include/ssl_key_handler.hpp
+++ b/include/ssl_key_handler.hpp
@@ -474,4 +474,65 @@
     }
     return mSslContext;
 }
+
+inline std::optional<boost::asio::ssl::context> getSSLClientContext()
+{
+    boost::asio::ssl::context sslCtx(boost::asio::ssl::context::tls_client);
+
+    boost::system::error_code ec;
+
+    // Support only TLS v1.2 & v1.3
+    sslCtx.set_options(boost::asio::ssl::context::default_workarounds |
+                           boost::asio::ssl::context::no_sslv2 |
+                           boost::asio::ssl::context::no_sslv3 |
+                           boost::asio::ssl::context::single_dh_use |
+                           boost::asio::ssl::context::no_tlsv1 |
+                           boost::asio::ssl::context::no_tlsv1_1,
+                       ec);
+    if (ec)
+    {
+        BMCWEB_LOG_ERROR << "SSL context set_options failed";
+        return std::nullopt;
+    }
+
+    // Add a directory containing certificate authority files to be used
+    // for performing verification.
+    sslCtx.set_default_verify_paths(ec);
+    if (ec)
+    {
+        BMCWEB_LOG_ERROR << "SSL context set_default_verify failed";
+        return std::nullopt;
+    }
+
+    // Verify the remote server's certificate
+    sslCtx.set_verify_mode(boost::asio::ssl::verify_peer, ec);
+    if (ec)
+    {
+        BMCWEB_LOG_ERROR << "SSL context set_verify_mode failed";
+        return std::nullopt;
+    }
+
+    // All cipher suites are set as per OWASP datasheet.
+    // https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html
+    constexpr const char* sslCiphers = "ECDHE-ECDSA-AES128-GCM-SHA256:"
+                                       "ECDHE-RSA-AES128-GCM-SHA256:"
+                                       "ECDHE-ECDSA-AES256-GCM-SHA384:"
+                                       "ECDHE-RSA-AES256-GCM-SHA384:"
+                                       "ECDHE-ECDSA-CHACHA20-POLY1305:"
+                                       "ECDHE-RSA-CHACHA20-POLY1305:"
+                                       "DHE-RSA-AES128-GCM-SHA256:"
+                                       "DHE-RSA-AES256-GCM-SHA384"
+                                       "TLS_AES_128_GCM_SHA256:"
+                                       "TLS_AES_256_GCM_SHA384:"
+                                       "TLS_CHACHA20_POLY1305_SHA256";
+
+    if (SSL_CTX_set_cipher_list(sslCtx.native_handle(), sslCiphers) != 1)
+    {
+        BMCWEB_LOG_ERROR << "SSL_CTX_set_cipher_list failed";
+        return std::nullopt;
+    }
+
+    return sslCtx;
+}
+
 } // namespace ensuressl