Add HTTPS support using BoringSSL.

Upstream implements HTTPS using GnuTLS but BoringSSL is preferred. This
CL removes all use of GnuTLS in src/microhttpd and implements HTTPS with
BoringSSL.

Bug: 23153045
Change-Id: Ibbe17e5e7b87fee32832bda30591f93ff023a807
diff --git a/Android.mk b/Android.mk
index 998c6da..10e7f6f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,11 +24,15 @@
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/src/include \
     $(LOCAL_PATH)/src/microhttpd \
+    external/boringssl/include \
+
+LOCAL_SHARED_LIBRARIES := libssl libcrypto
 
 LOCAL_SRC_FILES := \
     src/microhttpd/base64.c \
     src/microhttpd/basicauth.c \
     src/microhttpd/connection.c \
+    src/microhttpd/connection_https.c \
     src/microhttpd/daemon.c \
     src/microhttpd/digestauth.c \
     src/microhttpd/internal.c \
diff --git a/MHD_config.h b/MHD_config.h
index d439b52..185ea3b 100644
--- a/MHD_config.h
+++ b/MHD_config.h
@@ -58,7 +58,7 @@
 #define HAVE_FSEEKO 1
 
 /* Define to 1 if you have the <gcrypt.h> header file. */
-#define HAVE_GCRYPT_H 1
+/* #undef HAVE_GCRYPT_H */
 
 /* Define to 1 if you have `gmtime_s' function (only for W32). */
 /* #undef HAVE_GMTIME_S */
@@ -109,25 +109,25 @@
 #define HAVE_NETINET_TCP_H 1
 
 /* Define to 1 if you have the <openssl/engine.h> header file. */
-/* #undef HAVE_OPENSSL_ENGINE_H */
+#define HAVE_OPENSSL_ENGINE_H 1
 
 /* Define to 1 if you have the <openssl/err.h> header file. */
-/* #undef HAVE_OPENSSL_ERR_H */
+#define HAVE_OPENSSL_ERR_H 1
 
 /* Define to 1 if you have the <openssl/evp.h> header file. */
-/* #undef HAVE_OPENSSL_EVP_H */
+#define HAVE_OPENSSL_EVP_H 1
 
 /* Define to 1 if you have the <openssl/pem.h> header file. */
-/* #undef HAVE_OPENSSL_PEM_H */
+#define HAVE_OPENSSL_PEM_H 1
 
 /* Define to 1 if you have the <openssl/rand.h> header file. */
-/* #undef HAVE_OPENSSL_RAND_H */
+#define HAVE_OPENSSL_RAND_H 1
 
 /* Define to 1 if you have the <openssl/rsa.h> header file. */
-/* #undef HAVE_OPENSSL_RSA_H */
+#define HAVE_OPENSSL_RSA_H 1
 
 /* Define to 1 if you have the <openssl/sha.h> header file. */
-/* #undef HAVE_OPENSSL_SHA_H */
+#define HAVE_OPENSSL_SHA_H 1
 
 /* Define to 1 if you have the `poll' function. */
 #define HAVE_POLL 1
@@ -208,7 +208,7 @@
 /* #undef HAVE_WS2TCPIP_H */
 
 /* disable HTTPS support */
-#define HTTPS_SUPPORT 0
+#define HTTPS_SUPPORT 1
 
 /* Defined if libcurl supports AsynchDNS */
 /* #undef LIBCURL_FEATURE_ASYNCHDNS */
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index ca3bb86..b4ee0b7 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -1048,14 +1048,14 @@
 {
 
   /**
-   * Cipher algorithm used, of type "enum gnutls_cipher_algorithm".
+   * Cipher algorithm used, as a string.
    */
-  int /* enum gnutls_cipher_algorithm */ cipher_algorithm;
+  const char* cipher_algorithm;
 
   /**
-   * Protocol used, of type "enum gnutls_protocol".
+   * Protocol used, as a string.
    */
-  int /* enum gnutls_protocol */ protocol;
+  const char* protocol;
 
   /**
    * Connect socket
@@ -1063,14 +1063,14 @@
   MHD_socket connect_fd;
 
   /**
-   * GNUtls session handle, of type "gnutls_session_t".
+   * TLS session handle, of type "SSL".
    */
-  void * /* gnutls_session_t */ tls_session;
+  void * /* SSL */ tls_session;
 
   /**
-   * GNUtls client certificate handle, of type "gnutls_x509_crt_t".
+   * TLS client certificate handle, of type "X509".
    */
-  void * /* gnutls_x509_crt_t */ client_cert;
+  void * /* X509 */ client_cert;
 
   /**
    * Address information for the client.
@@ -1122,18 +1122,18 @@
   MHD_CONNECTION_INFO_CLIENT_ADDRESS,
 
   /**
-   * Get the gnuTLS session handle.
+   * Get the TLS session handle.
    * @ingroup request
    */
-  MHD_CONNECTION_INFO_GNUTLS_SESSION,
+  MHD_CONNECTION_INFO_TLS_SESSION,
 
   /**
    * Get the gnuTLS client certificate handle.  Dysfunctional (never
-   * implemented, deprecated).  Use #MHD_CONNECTION_INFO_GNUTLS_SESSION
-   * to get the `gnutls_session_t` and then call
-   * gnutls_certificate_get_peers().
+   * implemented, deprecated).  Use #MHD_CONNECTION_INFO_TLS_SESSION
+   * to get the `SSL` and then call
+   * SSL_get_peer_certificate() or SSL_get_peer_cert_chain().
    */
-  MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT,
+  MHD_CONNECTION_INFO_TLS_CLIENT_CERT,
 
   /**
    * Get the `struct MHD_Daemon *` responsible for managing this connection.
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 785fafd..ff57ac4 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -988,7 +988,7 @@
         {
 #if HTTPS_SUPPORT
 	case MHD_TLS_CONNECTION_INIT:
-	  if (0 == gnutls_record_get_direction (connection->tls_session))
+	  if (SSL_want_read (connection->tls_session))
             connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
 	  else
             connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
@@ -2781,14 +2781,14 @@
     case MHD_CONNECTION_INFO_CIPHER_ALGO:
       if (connection->tls_session == NULL)
 	return NULL;
-      connection->cipher = gnutls_cipher_get (connection->tls_session);
+      connection->cipher = SSL_CIPHER_get_name (SSL_get_current_cipher (connection->tls_session));
       return (const union MHD_ConnectionInfo *) &connection->cipher;
     case MHD_CONNECTION_INFO_PROTOCOL:
       if (connection->tls_session == NULL)
 	return NULL;
-      connection->protocol = gnutls_protocol_get_version (connection->tls_session);
+      connection->protocol = SSL_CIPHER_get_version (SSL_get_current_cipher (connection->tls_session));
       return (const union MHD_ConnectionInfo *) &connection->protocol;
-    case MHD_CONNECTION_INFO_GNUTLS_SESSION:
+    case MHD_CONNECTION_INFO_TLS_SESSION:
       if (connection->tls_session == NULL)
 	return NULL;
       return (const union MHD_ConnectionInfo *) &connection->tls_session;
diff --git a/src/microhttpd/connection_https.c b/src/microhttpd/connection_https.c
index 834d52e..83c2814 100644
--- a/src/microhttpd/connection_https.c
+++ b/src/microhttpd/connection_https.c
@@ -31,7 +31,7 @@
 #include "memorypool.h"
 #include "response.h"
 #include "reason_phrase.h"
-#include <gnutls/gnutls.h>
+#include <openssl/ssl.h>
 
 
 /**
@@ -46,19 +46,19 @@
 run_tls_handshake (struct MHD_Connection *connection)
 {
   int ret;
-
   connection->last_activity = MHD_monotonic_time();
   if (connection->state == MHD_TLS_CONNECTION_INIT)
     {
-      ret = gnutls_handshake (connection->tls_session);
-      if (ret == GNUTLS_E_SUCCESS)
+      ret = SSL_accept (connection->tls_session);
+      if (ret == 1)
 	{
 	  /* set connection state to enable HTTP processing */
 	  connection->state = MHD_CONNECTION_INIT;
 	  return MHD_YES;
 	}
-      if ( (ret == GNUTLS_E_AGAIN) ||
-	   (ret == GNUTLS_E_INTERRUPTED) )
+      int error = SSL_get_error (connection->tls_session, ret);
+      if ( (error == SSL_ERROR_WANT_READ) ||
+	   (error == SSL_ERROR_WANT_WRITE) )
 	{
 	  /* handshake not done */
 	  return MHD_YES;
@@ -150,10 +150,10 @@
       break;
       /* close connection if necessary */
     case MHD_CONNECTION_CLOSED:
-      gnutls_bye (connection->tls_session, GNUTLS_SHUT_RDWR);
+      SSL_shutdown (connection->tls_session);
       return MHD_connection_handle_idle (connection);
     default:
-      if ( (0 != gnutls_record_check_pending (connection->tls_session)) &&
+      if ( (0 != SSL_pending (connection->tls_session)) &&
 	   (MHD_YES != MHD_tls_connection_handle_read (connection)) )
 	return MHD_YES;
       return MHD_connection_handle_idle (connection);
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 1aa7d8d..40059cf 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -47,7 +47,7 @@
 
 #if HTTPS_SUPPORT
 #include "connection_https.h"
-#include <gcrypt.h>
+#include <openssl/ssl.h>
 #endif
 
 #if defined(HAVE_POLL_H) && defined(HAVE_POLL)
@@ -415,6 +415,92 @@
 
 
 #if HTTPS_SUPPORT
+
+static ssize_t
+recv_param_adapter (struct MHD_Connection *connection,
+                    void *other,
+                    size_t i);
+static ssize_t
+send_param_adapter (struct MHD_Connection *connection,
+                    const void *other,
+                    size_t i);
+
+// Internal functions for implementing OpenSSL BIO.
+static int
+MHD_bio_write (BIO* bio, const char* buf, int size)
+{
+  struct MHD_Connection* connection = (struct MHD_Connection*)bio->ptr;
+  BIO_clear_retry_flags (bio);
+  ssize_t written = send_param_adapter (connection, buf, size);
+  if (written < size)
+    {
+      BIO_set_retry_write (bio);
+    }
+  return written;
+}
+
+static int
+MHD_bio_read (BIO* bio, char* buf, int size)
+{
+  struct MHD_Connection* connection = (struct MHD_Connection*)bio->ptr;
+  BIO_clear_retry_flags (bio);
+  ssize_t read = recv_param_adapter (connection, buf, size);
+  if (read < size)
+    {
+      BIO_set_retry_read (bio);
+    }
+  return read;
+}
+
+static long
+MHD_bio_ctrl (BIO* bio, int cmd, long num, void* ptr)
+{
+  if (cmd == BIO_CTRL_FLUSH)
+    {
+      return 1;
+    }
+  return 0;
+}
+
+static int
+MHD_bio_new (BIO* bio)
+{
+  bio->shutdown = 0;
+  bio->init = 0;
+  bio->num = -1;  // not used.
+  return 1;
+}
+
+static int
+MHD_bio_free (BIO* bio)
+{
+  if (!bio)
+    return 0;
+
+  if (bio->init)
+    {
+      bio->ptr = NULL;
+      bio->init = 0;
+    }
+  return 1;
+}
+
+// Describes a BIO built on [send|recv]_param_adapter().
+BIO_METHOD MHD_bio_method =
+{
+    BIO_TYPE_SOURCE_SINK,
+    "mhd",          // name
+    MHD_bio_write,  // write function
+    MHD_bio_read,   // read function
+    NULL,           // puts function, not implemented
+    NULL,           // gets function, not implemented
+    MHD_bio_ctrl,   // control function
+    MHD_bio_new,    // creation
+    MHD_bio_free,   // free
+    NULL,           // callback function, not used
+};
+
+
 /**
  * Callback for receiving data from the socket.
  *
@@ -433,9 +519,8 @@
       connection->daemon->num_tls_read_ready--;
       connection->tls_read_ready = MHD_NO;
     }
-  res = gnutls_record_recv (connection->tls_session, other, i);
-  if ( (GNUTLS_E_AGAIN == res) ||
-       (GNUTLS_E_INTERRUPTED == res) )
+  res = SSL_read (connection->tls_session, other, i);
+  if ( res < 0 && SSL_want_read (connection->tls_session) )
     {
       MHD_set_socket_errno_ (EINTR);
 #if EPOLL_SUPPORT
@@ -474,9 +559,8 @@
 {
   int res;
 
-  res = gnutls_record_send (connection->tls_session, other, i);
-  if ( (GNUTLS_E_AGAIN == res) ||
-       (GNUTLS_E_INTERRUPTED == res) )
+  res = SSL_write (connection->tls_session, other, i);
+  if ( res < 0 && SSL_want_write (connection->tls_session) )
     {
       MHD_set_socket_errno_ (EINTR);
 #if EPOLL_SUPPORT
@@ -498,95 +582,6 @@
 
 
 /**
- * Read and setup our certificate and key.
- *
- * @param daemon handle to daemon to initialize
- * @return 0 on success
- */
-static int
-MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
-{
-  gnutls_datum_t key;
-  gnutls_datum_t cert;
-  int ret;
-
-#if GNUTLS_VERSION_MAJOR >= 3
-  if (NULL != daemon->cert_callback)
-    {
-      gnutls_certificate_set_retrieve_function2 (daemon->x509_cred,
-                                                 daemon->cert_callback);
-    }
-#endif
-  if (NULL != daemon->https_mem_trust)
-    {
-      cert.data = (unsigned char *) daemon->https_mem_trust;
-      cert.size = strlen (daemon->https_mem_trust);
-      if (gnutls_certificate_set_x509_trust_mem (daemon->x509_cred, &cert,
-						 GNUTLS_X509_FMT_PEM) < 0)
-	{
-#if HAVE_MESSAGES
-	  MHD_DLOG(daemon,
-		   "Bad trust certificate format\n");
-#endif
-	  return -1;
-	}
-    }
-
-  if (MHD_YES == daemon->have_dhparams)
-    {
-      gnutls_certificate_set_dh_params (daemon->x509_cred,
-                                        daemon->https_mem_dhparams);
-    }
-  /* certificate & key loaded from memory */
-  if ( (NULL != daemon->https_mem_cert) &&
-       (NULL != daemon->https_mem_key) )
-    {
-      key.data = (unsigned char *) daemon->https_mem_key;
-      key.size = strlen (daemon->https_mem_key);
-      cert.data = (unsigned char *) daemon->https_mem_cert;
-      cert.size = strlen (daemon->https_mem_cert);
-
-      if (NULL != daemon->https_key_password) {
-#if GNUTLS_VERSION_NUMBER >= 0x030111
-        ret = gnutls_certificate_set_x509_key_mem2 (daemon->x509_cred,
-                                                    &cert, &key,
-                                                    GNUTLS_X509_FMT_PEM,
-                                                    daemon->https_key_password,
-                                                    0);
-#else
-#if HAVE_MESSAGES
-	MHD_DLOG (daemon,
-                  "Failed to setup x509 certificate/key: pre 3.X.X version " \
-		  "of GnuTLS does not support setting key password");
-#endif
-	return -1;
-#endif
-      }
-      else
-        ret = gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
-                                                   &cert, &key,
-                                                   GNUTLS_X509_FMT_PEM);
-#if HAVE_MESSAGES
-      if (0 != ret)
-        MHD_DLOG (daemon,
-                  "GnuTLS failed to setup x509 certificate/key: %s\n",
-                  gnutls_strerror (ret));
-#endif
-      return ret;
-    }
-#if GNUTLS_VERSION_MAJOR >= 3
-  if (NULL != daemon->cert_callback)
-    return 0;
-#endif
-#if HAVE_MESSAGES
-  MHD_DLOG (daemon,
-            "You need to specify a certificate and key location\n");
-#endif
-  return -1;
-}
-
-
-/**
  * Initialize security aspects of the HTTPS daemon
  *
  * @param daemon handle to daemon to initialize
@@ -595,21 +590,140 @@
 static int
 MHD_TLS_init (struct MHD_Daemon *daemon)
 {
-  switch (daemon->cred_type)
+  int ret;
+  daemon->tls_context = SSL_CTX_new (TLSv1_2_server_method());
+  if (NULL == daemon->tls_context)
+    return -1;
+  if (NULL != daemon->https_mem_trust)
     {
-    case GNUTLS_CRD_CERTIFICATE:
-      if (0 !=
-          gnutls_certificate_allocate_credentials (&daemon->x509_cred))
-        return GNUTLS_E_MEMORY_ERROR;
-      return MHD_init_daemon_certificate (daemon);
-    default:
+      ret = 0;
+      BIO* mem_bio = BIO_new_mem_buf ((void*)daemon->https_mem_trust, -1);
+      X509* x509 = PEM_read_bio_X509 (mem_bio, NULL, NULL, NULL);
+      BIO_free(mem_bio);
+      if (x509 != NULL)
+        {
+          ret = SSL_CTX_add_client_CA (daemon->tls_context, x509);
+        }
+      if (ret == 0)
+        {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Bad trust certificate format\n");
+#endif
+          return -1;
+        }
+    }
+
+  if (NULL != daemon->https_mem_dhparams)
+    {
+      ret = 0;
+      BIO* mem_bio = BIO_new_mem_buf ((void*)daemon->https_mem_dhparams, -1);
+      DH* dh = PEM_read_bio_DHparams (mem_bio, NULL, NULL, NULL);
+      BIO_free (mem_bio);
+      if (dh != NULL)
+        {
+          ret = SSL_CTX_set_tmp_dh (daemon->tls_context, dh);
+        }
+      if (ret == 0)
+        {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Bad DH parameters format\n");
+#endif
+          return -1;
+        }
+    }
+
+  /* certificate & key loaded from memory */
+  if ( (NULL != daemon->https_mem_cert) &&
+       (NULL != daemon->https_mem_key) )
+    {
+      ret = 0;
+      BIO* mem_bio = BIO_new_mem_buf ((void*)daemon->https_mem_key, -1);
+      EVP_PKEY* key = PEM_read_bio_PrivateKey (mem_bio, NULL, NULL,
+                                               (void*)daemon->https_key_password);
+      BIO_free (mem_bio);
+      if (key != NULL)
+        {
+          ret = SSL_CTX_use_PrivateKey (daemon->tls_context, key);
+        }
+      if (ret == 0)
+        {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Bad private key format\n");
+#endif
+          return -1;
+        }
+      ret = 0;
+      mem_bio = BIO_new_mem_buf ((void*)daemon->https_mem_cert, -1);
+      X509* x509 = PEM_read_bio_X509 (mem_bio, NULL, NULL, NULL);
+      BIO_free (mem_bio);
+      if (x509 != NULL)
+        {
+          ret = SSL_CTX_use_certificate (daemon->tls_context, x509);
+        }
+      if (ret == 0)
+        {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Bad certificate format\n");
+#endif
+          return -1;
+        }
+      if (1 != SSL_CTX_check_private_key (daemon->tls_context))
+         {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Invalid key / certificate combination\n");
+#endif
+          return -1;
+        }
+    }
+  else
+    {
 #if HAVE_MESSAGES
       MHD_DLOG (daemon,
-                "Error: invalid credentials type %d specified.\n",
-                daemon->cred_type);
+                "You need to specify a certificate and key location\n");
 #endif
       return -1;
     }
+  if (NULL != daemon->https_mem_cipher)
+    {
+      ret = SSL_CTX_set_cipher_list (daemon->tls_context,
+                                     daemon->https_mem_cipher);
+      if (ret == 0)
+        {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Bad cipher string format\n");
+#endif
+          return -1;
+        }
+    }
+  else
+    {
+      ret = SSL_CTX_set_cipher_list (daemon->tls_context,
+                                     "ECDHE-ECDSA-AES128-GCM-SHA256:"
+                                     "ECDHE-ECDSA-AES256-GCM-SHA384:"
+                                     "ECDHE-RSA-AES128-GCM-SHA256:"
+                                     "ECDHE-RSA-AES256-GCM-SHA384");
+      if (ret == 0)
+         {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon,
+                    "Failed to setup default cipher string\n");
+#endif
+          return -1;
+        }
+    }
+  return 0;
+}
+
+static void
+MHD_TLS_deinit (struct MHD_Daemon *daemon)
+{
+  SSL_CTX_free (daemon->tls_context);
 }
 #endif
 
@@ -1450,44 +1564,15 @@
       connection->send_cls = &send_tls_adapter;
       connection->state = MHD_TLS_CONNECTION_INIT;
       MHD_set_https_callbacks (connection);
-      gnutls_init (&connection->tls_session, GNUTLS_SERVER);
-      gnutls_priority_set (connection->tls_session,
-			   daemon->priority_cache);
-      switch (daemon->cred_type)
+      connection->tls_session = SSL_new (daemon->tls_context);
+      BIO* bio = BIO_new (&MHD_bio_method);
+      if (bio)
         {
-          /* set needed credentials for certificate authentication. */
-        case GNUTLS_CRD_CERTIFICATE:
-          gnutls_credentials_set (connection->tls_session,
-				  GNUTLS_CRD_CERTIFICATE,
-				  daemon->x509_cred);
-          break;
-        default:
-#if HAVE_MESSAGES
-          MHD_DLOG (connection->daemon,
-                    "Failed to setup TLS credentials: unknown credential type %d\n",
-                    daemon->cred_type);
-#endif
-          if (0 != MHD_socket_close_ (client_socket))
-	    MHD_PANIC ("close failed\n");
-          MHD_ip_limit_del (daemon, addr, addrlen);
-          free (connection->addr);
-          free (connection);
-          MHD_PANIC ("Unknown credential type");
-#if EINVAL
-	  errno = EINVAL;
-#endif
- 	  return MHD_NO;
+          bio->ptr = connection;
+          bio->init = 1;
         }
-      gnutls_transport_set_ptr (connection->tls_session,
-				(gnutls_transport_ptr_t) connection);
-      gnutls_transport_set_pull_function (connection->tls_session,
-					  (gnutls_pull_func) &recv_param_adapter);
-      gnutls_transport_set_push_function (connection->tls_session,
-					  (gnutls_push_func) &send_param_adapter);
-
-      if (daemon->https_mem_trust)
-	  gnutls_certificate_server_set_request (connection->tls_session,
-						 GNUTLS_CERT_REQUEST);
+      SSL_set_bio (connection->tls_session, bio, bio);
+      SSL_set_app_data (connection->tls_session, connection);
     }
 #endif
 
@@ -2000,7 +2085,7 @@
       MHD_pool_destroy (pos->pool);
 #if HTTPS_SUPPORT
       if (NULL != pos->tls_session)
-	gnutls_deinit (pos->tls_session);
+ 	SSL_free (pos->tls_session);
 #endif
       if (NULL != daemon->notify_connection)
         daemon->notify_connection (daemon->notify_connection_cls,
@@ -2111,7 +2196,7 @@
 	    earliest_deadline = pos->last_activity + pos->connection_timeout;
 #if HTTPS_SUPPORT
 	  if (  (0 != (daemon->options & MHD_USE_SSL)) &&
-		(0 != gnutls_record_check_pending (pos->tls_session)) )
+		(0 != SSL_pending (pos->tls_session)) )
 	    earliest_deadline = 0;
 #endif
 	  have_timeout = MHD_YES;
@@ -2127,7 +2212,7 @@
 	earliest_deadline = pos->last_activity + pos->connection_timeout;
 #if HTTPS_SUPPORT
       if (  (0 != (daemon->options & MHD_USE_SSL)) &&
-	    (0 != gnutls_record_check_pending (pos->tls_session)) )
+	    (0 != SSL_pending (pos->tls_session)) )
 	earliest_deadline = 0;
 #endif
       have_timeout = MHD_YES;
@@ -2189,11 +2274,11 @@
 
   /* select connection thread handling type */
   if ( (MHD_INVALID_SOCKET != (ds = daemon->socket_fd)) &&
-       (FD_ISSET (ds, read_fd_set)) )
+       (FD_ISSET (ds, (fd_set*)read_fd_set)) )
     (void) MHD_accept_connection (daemon);
   /* drain signaling pipe to avoid spinning select */
   if ( (MHD_INVALID_PIPE_ != daemon->wpipe[0]) &&
-       (FD_ISSET (daemon->wpipe[0], read_fd_set)) )
+       (FD_ISSET (daemon->wpipe[0], (fd_set*)read_fd_set)) )
     (void) MHD_pipe_read_ (daemon->wpipe[0], &tmp, sizeof (tmp));
 
   if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
@@ -2209,7 +2294,7 @@
 	  switch (pos->event_loop_info)
 	    {
 	    case MHD_EVENT_LOOP_INFO_READ:
-	      if ( (FD_ISSET (ds, read_fd_set))
+	      if ( (FD_ISSET (ds, (fd_set*)read_fd_set))
 #if HTTPS_SUPPORT
 		   || (MHD_YES == pos->tls_read_ready)
 #endif
@@ -2217,14 +2302,14 @@
 		pos->read_handler (pos);
 	      break;
 	    case MHD_EVENT_LOOP_INFO_WRITE:
-	      if ( (FD_ISSET (ds, read_fd_set)) &&
+	      if ( (FD_ISSET (ds, (fd_set*)read_fd_set)) &&
 		   (pos->read_buffer_size > pos->read_buffer_offset) )
 		pos->read_handler (pos);
-	      if (FD_ISSET (ds, write_fd_set))
+	      if (FD_ISSET (ds, (fd_set*)write_fd_set))
 		pos->write_handler (pos);
 	      break;
 	    case MHD_EVENT_LOOP_INFO_BLOCK:
-	      if ( (FD_ISSET (ds, read_fd_set)) &&
+	      if ( (FD_ISSET (ds, (fd_set*)read_fd_set)) &&
 		   (pos->read_buffer_size > pos->read_buffer_offset) )
 		pos->read_handler (pos);
 	      break;
@@ -3150,118 +3235,93 @@
 #if HTTPS_SUPPORT
         case MHD_OPTION_HTTPS_MEM_KEY:
 	  if (0 != (daemon->options & MHD_USE_SSL))
-	    daemon->https_mem_key = va_arg (ap, const char *);
-#if HAVE_MESSAGES
+	    {
+	      daemon->https_mem_key = va_arg (ap, const char *);
+	    }
 	  else
+	    {
+#if HAVE_MESSAGES
 	    MHD_DLOG (daemon,
 		      "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
 		      opt);
 #endif
+	    }
           break;
         case MHD_OPTION_HTTPS_KEY_PASSWORD:
 	  if (0 != (daemon->options & MHD_USE_SSL))
-	    daemon->https_key_password = va_arg (ap, const char *);
-#if HAVE_MESSAGES
+	    {
+	      daemon->https_key_password = va_arg (ap, const char *);
+	    }
 	  else
+	    {
+#if HAVE_MESSAGES
 	    MHD_DLOG (daemon,
 		      "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
 		      opt);
 #endif
+	    }
           break;
         case MHD_OPTION_HTTPS_MEM_CERT:
 	  if (0 != (daemon->options & MHD_USE_SSL))
-	    daemon->https_mem_cert = va_arg (ap, const char *);
-#if HAVE_MESSAGES
+	    {
+	      daemon->https_mem_cert = va_arg (ap, const char *);
+	    }
 	  else
+	    {
+#if HAVE_MESSAGES
 	    MHD_DLOG (daemon,
 		      "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
 		      opt);
 #endif
+	    }
           break;
         case MHD_OPTION_HTTPS_MEM_TRUST:
 	  if (0 != (daemon->options & MHD_USE_SSL))
-	    daemon->https_mem_trust = va_arg (ap, const char *);
-#if HAVE_MESSAGES
+	    {
+	      daemon->https_mem_trust = va_arg (ap, const char *);
+	    }
 	  else
+	    {
+#if HAVE_MESSAGES
 	    MHD_DLOG (daemon,
 		      "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
 		      opt);
 #endif
+	    }
           break;
 	case MHD_OPTION_HTTPS_CRED_TYPE:
-	  daemon->cred_type = (gnutls_credentials_type_t) va_arg (ap, int);
 	  break;
         case MHD_OPTION_HTTPS_MEM_DHPARAMS:
-          if (0 != (daemon->options & MHD_USE_SSL))
-            {
-              const char *arg = va_arg (ap, const char *);
-              gnutls_datum_t dhpar;
-
-              if (gnutls_dh_params_init (&daemon->https_mem_dhparams) < 0)
-                {
+	  if (0 != (daemon->options & MHD_USE_SSL))
+	    {
+	      daemon->https_mem_dhparams = va_arg (ap, const char *);
+	    }
+	  else
+	    {
 #if HAVE_MESSAGES
-                  MHD_DLOG(daemon,
-                           "Error initializing DH parameters\n");
+	    MHD_DLOG (daemon,
+		      "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
+		      opt);
 #endif
-                  return MHD_NO;
-                }
-              dhpar.data = (unsigned char *) arg;
-              dhpar.size = strlen (arg);
-              if (gnutls_dh_params_import_pkcs3 (daemon->https_mem_dhparams, &dhpar,
-                                                 GNUTLS_X509_FMT_PEM) < 0)
-                {
-#if HAVE_MESSAGES
-                  MHD_DLOG(daemon,
-                           "Bad Diffie-Hellman parameters format\n");
-#endif
-                  gnutls_dh_params_deinit (daemon->https_mem_dhparams);
-                  return MHD_NO;
-                }
-              daemon->have_dhparams = MHD_YES;
-            }
-          else
-            {
-#if HAVE_MESSAGES
-              MHD_DLOG (daemon,
-                        "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
-                        opt);
-#endif
-              return MHD_NO;
-            }
+	    }
           break;
         case MHD_OPTION_HTTPS_PRIORITIES:
 	  if (0 != (daemon->options & MHD_USE_SSL))
 	    {
-	      gnutls_priority_deinit (daemon->priority_cache);
-	      ret = gnutls_priority_init (&daemon->priority_cache,
-					  pstr = va_arg (ap, const char*),
-					  NULL);
-	      if (GNUTLS_E_SUCCESS != ret)
-	      {
+	      daemon->https_mem_cipher = va_arg (ap, const char *);
+	    }
+	  else
+	    {
 #if HAVE_MESSAGES
-		MHD_DLOG (daemon,
-			  "Setting priorities to `%s' failed: %s\n",
-			  pstr,
-			  gnutls_strerror (ret));
+	      MHD_DLOG (daemon,
+			"MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
+			opt);
 #endif
-		daemon->priority_cache = NULL;
-		return MHD_NO;
-	      }
 	    }
           break;
         case MHD_OPTION_HTTPS_CERT_CALLBACK:
-#if GNUTLS_VERSION_MAJOR < 3
-#if HAVE_MESSAGES
-          MHD_DLOG (daemon,
-                    "MHD_OPTION_HTTPS_CERT_CALLBACK requires building MHD with GnuTLS >= 3.0\n");
-#endif
-          return MHD_NO;
-#else
-          if (0 != (daemon->options & MHD_USE_SSL))
-            daemon->cert_callback = va_arg (ap, gnutls_certificate_retrieve_function2 *);
           break;
 #endif
-#endif
 #ifdef DAUTH_SUPPORT
 	case MHD_OPTION_DIGEST_AUTH_RANDOM:
 	  daemon->digest_auth_rand_size = va_arg (ap, size_t);
@@ -3600,14 +3660,6 @@
   daemon->epoll_fd = -1;
 #endif
   /* try to open listen socket */
-#if HTTPS_SUPPORT
-  if (0 != (flags & MHD_USE_SSL))
-    {
-      gnutls_priority_init (&daemon->priority_cache,
-			    "NORMAL",
-			    NULL);
-    }
-#endif
   daemon->socket_fd = MHD_INVALID_SOCKET;
   daemon->listening_address_reuse = 0;
   daemon->options = flags;
@@ -3672,21 +3724,10 @@
   daemon->digest_auth_random = NULL;
   daemon->nonce_nc_size = 4; /* tiny */
 #endif
-#if HTTPS_SUPPORT
-  if (0 != (flags & MHD_USE_SSL))
-    {
-      daemon->cred_type = GNUTLS_CRD_CERTIFICATE;
-    }
-#endif
 
 
   if (MHD_YES != parse_options_va (daemon, &servaddr, ap))
     {
-#if HTTPS_SUPPORT
-      if ( (0 != (flags & MHD_USE_SSL)) &&
-	   (NULL != daemon->priority_cache) )
-	gnutls_priority_deinit (daemon->priority_cache);
-#endif
       free (daemon);
       return NULL;
     }
@@ -3700,10 +3741,6 @@
 	  MHD_DLOG (daemon,
 		    "Specified value for NC_SIZE too large\n");
 #endif
-#if HTTPS_SUPPORT
-	  if (0 != (flags & MHD_USE_SSL))
-	    gnutls_priority_deinit (daemon->priority_cache);
-#endif
 	  free (daemon);
 	  return NULL;
 	}
@@ -3715,10 +3752,6 @@
 		    "Failed to allocate memory for nonce-nc map: %s\n",
 		    MHD_strerror_ (errno));
 #endif
-#if HTTPS_SUPPORT
-	  if (0 != (flags & MHD_USE_SSL))
-	    gnutls_priority_deinit (daemon->priority_cache);
-#endif
 	  free (daemon);
 	  return NULL;
 	}
@@ -3730,10 +3763,6 @@
       MHD_DLOG (daemon,
 		"MHD failed to initialize nonce-nc mutex\n");
 #endif
-#if HTTPS_SUPPORT
-      if (0 != (flags & MHD_USE_SSL))
-	gnutls_priority_deinit (daemon->priority_cache);
-#endif
       free (daemon->nnc);
       free (daemon);
       return NULL;
@@ -4280,10 +4309,6 @@
   free (daemon->nnc);
   (void) MHD_mutex_destroy_ (&daemon->nnc_lock);
 #endif
-#if HTTPS_SUPPORT
-  if (0 != (flags & MHD_USE_SSL))
-    gnutls_priority_deinit (daemon->priority_cache);
-#endif
   free (daemon);
   return NULL;
 }
@@ -4513,16 +4538,9 @@
 
   /* TLS clean up */
 #if HTTPS_SUPPORT
-  if (MHD_YES == daemon->have_dhparams)
-    {
-      gnutls_dh_params_deinit (daemon->https_mem_dhparams);
-      daemon->have_dhparams = MHD_NO;
-    }
   if (0 != (daemon->options & MHD_USE_SSL))
     {
-      gnutls_priority_deinit (daemon->priority_cache);
-      if (daemon->x509_cred)
-        gnutls_certificate_free_credentials (daemon->x509_cred);
+      MHD_TLS_deinit (daemon);
     }
 #endif
 #if EPOLL_SUPPORT
@@ -4679,11 +4697,7 @@
       return MHD_NO;
 #endif
     case MHD_FEATURE_HTTPS_CERT_CALLBACK:
-#if HTTPS_SUPPORT && GNUTLS_VERSION_MAJOR >= 3
-      return MHD_YES;
-#else
       return MHD_NO;
-#endif
     case MHD_FEATURE_IPv6:
 #ifdef HAVE_INET6
       return MHD_YES;
@@ -4745,7 +4759,7 @@
       return MHD_NO;
 #endif
     case MHD_FEATURE_HTTPS_KEY_PASSWORD:
-#if HTTPS_SUPPORT && GNUTLS_VERSION_NUMBER >= 0x030111
+#if HTTPS_SUPPORT
       return MHD_YES;
 #else
       return MHD_NO;
@@ -4755,44 +4769,6 @@
 }
 
 
-#if HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600
-#if defined(MHD_USE_POSIX_THREADS)
-GCRY_THREAD_OPTION_PTHREAD_IMPL;
-#elif defined(MHD_W32_MUTEX_)
-static int gcry_w32_mutex_init (void **ppmtx)
-{
-  *ppmtx = malloc (sizeof (MHD_mutex_));
-
-  if (NULL == *ppmtx)
-    return ENOMEM;
-
-  if (MHD_YES != MHD_mutex_create_ ((MHD_mutex_*)*ppmtx))
-    {
-      free (*ppmtx);
-      *ppmtx = NULL;
-      return EPERM;
-    }
-
-  return 0;
-}
-static int gcry_w32_mutex_destroy (void **ppmtx)
-  { int res = (MHD_YES == MHD_mutex_destroy_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1;
-    free (*ppmtx); return res; }
-static int gcry_w32_mutex_lock (void **ppmtx)
-  { return (MHD_YES == MHD_mutex_lock_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1; }
-static int gcry_w32_mutex_unlock (void **ppmtx)
-  { return (MHD_YES == MHD_mutex_unlock_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1; }
-
-static struct gcry_thread_cbs gcry_threads_w32 = {
-  (GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)),
-  NULL, gcry_w32_mutex_init, gcry_w32_mutex_destroy,
-  gcry_w32_mutex_lock, gcry_w32_mutex_unlock,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-
-#endif // defined(MHD_W32_MUTEX_)
-#endif // HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600
-
-
 /**
  * Initialize do setup work.
  */
@@ -4810,29 +4786,13 @@
     MHD_PANIC ("Winsock version 2.2 is not available\n");
 #endif
 #if HTTPS_SUPPORT
-#if GCRYPT_VERSION_NUMBER < 0x010600
-#if defined(MHD_USE_POSIX_THREADS)
-  if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
-    MHD_PANIC ("Failed to initialise multithreading in libgcrypt\n");
-#elif defined(MHD_W32_MUTEX_)
-  if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_w32))
-    MHD_PANIC ("Failed to initialise multithreading in libgcrypt\n");
-#endif // defined(MHD_W32_MUTEX_)
-  gcry_check_version (NULL);
-#else
-  if (NULL == gcry_check_version ("1.6.0"))
-    MHD_PANIC ("libgcrypt is too old. MHD was compiled for libgcrypt 1.6.0 or newer\n");
-#endif
-  gnutls_global_init ();
+  SSL_library_init();
 #endif
 }
 
 
 void MHD_fini(void)
 {
-#if HTTPS_SUPPORT
-  gnutls_global_deinit ();
-#endif
 #ifdef _WIN32
   if (mhd_winsock_inited_)
     WSACleanup();
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 286aee6..fa751be 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -31,10 +31,7 @@
 #include "microhttpd.h"
 #include "platform_interface.h"
 #if HTTPS_SUPPORT
-#include <gnutls/gnutls.h>
-#if GNUTLS_VERSION_MAJOR >= 3
-#include <gnutls/abstract.h>
-#endif
+#include <openssl/ssl.h>
 #endif
 #if EPOLL_SUPPORT
 #include <sys/epoll.h>
@@ -841,17 +838,17 @@
   /**
    * State required for HTTPS/SSL/TLS support.
    */
-  gnutls_session_t tls_session;
+  SSL* tls_session;
 
   /**
    * Memory location to return for protocol session info.
    */
-  int protocol;
+  const char* protocol;
 
   /**
    * Memory location to return for protocol session info.
    */
-  int cipher;
+  const char* cipher;
 
   /**
    * Could it be that we are ready to read due to TLS buffers
@@ -1193,42 +1190,14 @@
   uint16_t port;
 
 #if HTTPS_SUPPORT
+  SSL_CTX* tls_context;
   /**
-   * Desired cipher algorithms.
-   */
-  gnutls_priority_t priority_cache;
-
-  /**
-   * What kind of credentials are we offering
-   * for SSL/TLS?
-   */
-  gnutls_credentials_type_t cred_type;
-
-  /**
-   * Server x509 credentials
-   */
-  gnutls_certificate_credentials_t x509_cred;
-
-  /**
-   * Diffie-Hellman parameters
-   */
-  gnutls_dh_params_t dh_params;
-
-#if GNUTLS_VERSION_MAJOR >= 3
-  /**
-   * Function that can be used to obtain the certificate.  Needed
-   * for SNI support.  See #MHD_OPTION_HTTPS_CERT_CALLBACK.
-   */
-  gnutls_certificate_retrieve_function2 *cert_callback;
-#endif
-
-  /**
-   * Pointer to our SSL/TLS key (in ASCII) in memory.
+   * Pointer to our SSL/TLS key (in PEM) in memory.
    */
   const char *https_mem_key;
 
   /**
-   * Pointer to our SSL/TLS certificate (in ASCII) in memory.
+   * Pointer to our SSL/TLS certificate (in PEM) in memory.
    */
   const char *https_mem_cert;
 
@@ -1238,19 +1207,19 @@
   const char *https_key_password;
 
   /**
-   * Pointer to our SSL/TLS certificate authority (in ASCII) in memory.
+   * Pointer to our SSL/TLS certificate authority (in PEM) in memory.
    */
   const char *https_mem_trust;
 
   /**
-   * Our Diffie-Hellman parameters in memory.
+   * Our Diffie-Hellman parameters (in PEM) in memory.
    */
-  gnutls_dh_params_t https_mem_dhparams;
+  const char *https_mem_dhparams;
 
   /**
-   * #MHD_YES if we have initialized @e https_mem_dhparams.
+   * Pointer to SSL/TLS cipher string in memory.
    */
-  int have_dhparams;
+  const char *https_mem_cipher;
 
   /**
    * For how many connections do we have 'tls_read_ready' set to MHD_YES?