Procházet zdrojové kódy

Implemented initialisation of daemon's GnuTLS data

Evgeny Grin (Karlson2k) před 1 rokem
rodič
revize
cd6fda427c

+ 54 - 5
src/include/d_options.rec

@@ -149,18 +149,67 @@ Argument1: enum MHD_TlsBackend backend
 Description1: the TLS backend to use,
 Description1: the TLS backend to use,
 + #MHD_TLS_BACKEND_NONE for non-TLS (plain TCP) connections
 + #MHD_TLS_BACKEND_NONE for non-TLS (plain TCP) connections
 
 
-Name: tls_key_cert
+Name: tls_cert_key
 Value: 121
 Value: 121
 Comment: Provide TLS key and certificate data in-memory.
 Comment: Provide TLS key and certificate data in-memory.
 + Works only if TLS mode is enabled.
 + Works only if TLS mode is enabled.
 Type: struct MHD_DaemonOptionValueTlsCert
 Type: struct MHD_DaemonOptionValueTlsCert
-Argument1: const char *mem_key
-Description1: the private key loaded into memory (not a filename)
-Argument2: const char *mem_cert
-Description2: the certificate loaded into memory (not a filename)
+Argument1: /* const */ char *mem_cert
+Description1: The X.509 certificates chain in PEM format loaded into memory (not a filename).
++ The first certificate must be the server certificate, following by the chain of signing
++ certificates up to (but not including) CA root certificate.
+Argument2: const char *mem_key
+Description2: the private key in PEM format loaded into memory (not a filename)
 Argument3: const char *mem_pass
 Argument3: const char *mem_pass
 Description3: the option passphrase phrase to decrypt the private key,
 Description3: the option passphrase phrase to decrypt the private key,
 + could be NULL is private does not need a password
 + could be NULL is private does not need a password
+CustomSetter: /* custom setter */
++ if ((NULL == option->val.tls_cert_key.v_mem_cert)
++     || (NULL == option->val.tls_cert_key.v_mem_key))
++   return MHD_SC_TLS_CONF_BAD_CERT;
++ else
++ {
++   size_t cert_size;
++   size_t key_size;
++   size_t pass_size;
++   cert_size = strlen (option->val.tls_cert_key.v_mem_cert);
++   key_size = strlen (option->val.tls_cert_key.v_mem_key);
++   if ((0 == cert_size) 
++       || (0 == key_size))
++     return MHD_SC_TLS_CONF_BAD_CERT;
++   ++cert_size; /* Space for zero-termination */
++   ++key_size;  /* Space for zero-termination */
++   if (NULL != option->val.tls_cert_key.v_mem_pass)
++     pass_size = strlen (option->val.tls_cert_key.v_mem_cert);
++   else
++     pass_size = 0;
++   if (0 != pass_size)
++     ++pass_size; /* Space for zero-termination */
++   if (NULL != settings->tls_cert_key.v_mem_cert)
++     free (settings->tls_cert_key.v_mem_cert); // TODO: Support multiple certificates!!
++   settings->tls_cert_key.v_mem_cert = malloc (cert_size + key_size + pass_size);
++   if (NULL == settings->tls_cert_key.v_mem_cert)
++     return MHD_SC_DAEMON_MALLOC_FAILURE;
++   memcpy (settings->tls_cert_key.v_mem_cert,
++           option->val.tls_cert_key.v_mem_cert,
++           cert_size);
++   memcpy (settings->tls_cert_key.v_mem_cert + cert_size,
++           option->val.tls_cert_key.v_mem_key,
++           key_size);
++   settings->tls_cert_key.v_mem_key =
++     settings->tls_cert_key.v_mem_cert + cert_size;
++   if (0 != pass_size)
++   {
++     memcpy (settings->tls_cert_key.v_mem_cert + cert_size + key_size,
++             option->val.tls_cert_key.v_mem_pass,
++             pass_size);
++     settings->tls_cert_key.v_mem_pass =
++       settings->tls_cert_key.v_mem_cert + cert_size + key_size;
++   }
++   else
++     settings->tls_cert_key.v_mem_pass = NULL;
++ }
+
 
 
 Name: tls_client_ca
 Name: tls_client_ca
 Value: 122
 Value: 122

+ 40 - 21
src/include/microhttpd2.h

@@ -459,6 +459,7 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
   ,
   ,
   /**
   /**
    * Failed to allocate memory for the daemon resources.
    * Failed to allocate memory for the daemon resources.
+   * TODO: combine similar error codes for daemon
    */
    */
   MHD_SC_DAEMON_MALLOC_FAILURE = 30081
   MHD_SC_DAEMON_MALLOC_FAILURE = 30081
   ,
   ,
@@ -713,12 +714,6 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_TLS_DISABLED = 50000
   MHD_SC_TLS_DISABLED = 50000
   ,
   ,
-  /**
-   * The application attempted to setup TLS parameters before
-   * enabling TLS.
-   */
-  MHD_SC_TLS_BACKEND_UNINITIALIZED = 50003
-  ,
   /**
   /**
    * The selected TLS backend does not yet support this operation.
    * The selected TLS backend does not yet support this operation.
    */
    */
@@ -1286,6 +1281,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_LIB_INIT_GLOBAL_FAILED = 51000
   MHD_SC_LIB_INIT_GLOBAL_FAILED = 51000
   ,
   ,
+  /**
+   * Failed to initialise TLS context for the daemon
+   */
+  MHD_SC_DAEMON_TLS_INIT_FAILED = 51200
+  ,
   /**
   /**
    * Something wrong in the internal MHD logic.
    * Something wrong in the internal MHD logic.
    * This error should be never returned if MHD works as expected.
    * This error should be never returned if MHD works as expected.
@@ -1309,17 +1309,6 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 60001
   MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 60001
   ,
   ,
-  /**
-   * The application requested an unsupported TLS backend to be used.
-   */
-  MHD_SC_TLS_BACKEND_UNSUPPORTED = 60003
-  ,
-  /**
-   * The application requested a TLS cipher suite which is not
-   * supported by the selected backend.
-   */
-  MHD_SC_TLS_CIPHERS_INVALID = 60004
-  ,
   /**
   /**
    * MHD is closing a connection because the application
    * MHD is closing a connection because the application
    * logic to generate the response data failed.
    * logic to generate the response data failed.
@@ -1390,6 +1379,34 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL = 60016
   MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL = 60016
   ,
   ,
+  /**
+   * The application requested an unsupported TLS backend to be used.
+   */
+  MHD_SC_TLS_BACKEND_UNSUPPORTED = 60020
+  ,
+  /**
+   * The application attempted to setup TLS parameters before
+   * enabling TLS.
+   */
+  MHD_SC_TLS_BACKEND_UNINITIALIZED = 60021
+  ,
+  /**
+   * The application requested a TLS backend which cannot be used due
+   * to missing TLS dynamic library or backend initialisation problem.
+   */
+  MHD_SC_TLS_BACKEND_UNAVAILABLE = 60022
+  ,
+  /**
+   * Provided TLS certificate and/or private key are incorrect
+   */
+  MHD_SC_TLS_CONF_BAD_CERT = 60023
+  ,
+  /**
+   * The application requested a TLS cipher suite which is not
+   * supported by the selected backend.
+   */
+  MHD_SC_TLS_CIPHERS_INVALID = 60024
+  ,
   /**
   /**
    * The response header name has forbidden characters or token
    * The response header name has forbidden characters or token
    */
    */
@@ -3954,16 +3971,18 @@ MHD_D_OPTION_TLS (
 /**
 /**
  * Provide TLS key and certificate data in-memory.
  * Provide TLS key and certificate data in-memory.
  * Works only if TLS mode is enabled.
  * Works only if TLS mode is enabled.
- * @param mem_key the private key loaded into memory (not a filename)
- * @param mem_cert the certificate loaded into memory (not a filename)
+ * @param mem_cert The X.509 certificates chain in PEM format loaded into memory (not a filename).
+ *   The first certificate must be the server certificate, following by the chain of signing
+ *   certificates up to (but not including) CA root certificate.
+ * @param mem_key the private key in PEM format loaded into memory (not a filename)
  * @param mem_pass the option passphrase phrase to decrypt the private key,
  * @param mem_pass the option passphrase phrase to decrypt the private key,
  *   could be NULL is private does not need a password
  *   could be NULL is private does not need a password
  * @return structure with the requested setting
  * @return structure with the requested setting
  */
  */
 struct MHD_DaemonOptionAndValue
 struct MHD_DaemonOptionAndValue
-MHD_D_OPTION_TLS_KEY_CERT (
+MHD_D_OPTION_TLS_CERT_KEY (
+  /* const */ char *mem_cert,
   const char *mem_key,
   const char *mem_key,
-  const char *mem_cert,
   const char *mem_pass
   const char *mem_pass
   );
   );
 
 

+ 32 - 24
src/include/microhttpd2_generated_daemon_options.h

@@ -108,7 +108,7 @@ Works only when #MHD_D_OPTION_BIND_PORT() or #MHD_D_OPTION_BIND_SA() are used.
    * Provide TLS key and certificate data in-memory.
    * Provide TLS key and certificate data in-memory.
    * Works only if TLS mode is enabled.
    * Works only if TLS mode is enabled.
    */
    */
-  MHD_D_O_TLS_KEY_CERT = 121
+  MHD_D_O_TLS_CERT_KEY = 121
   ,
   ,
 
 
   /**
   /**
@@ -424,19 +424,21 @@ struct MHD_DaemonOptionValueTFO
 };
 };
 
 
 /**
 /**
- * Data for #MHD_D_O_TLS_KEY_CERT
+ * Data for #MHD_D_O_TLS_CERT_KEY
  */
  */
 struct MHD_DaemonOptionValueTlsCert
 struct MHD_DaemonOptionValueTlsCert
 {
 {
   /**
   /**
-   * the private key loaded into memory (not a filename)
+   * The X.509 certificates chain in PEM format loaded into memory (not a filename).
+   * The first certificate must be the server certificate, following by the chain of signing
+   * certificates up to (but not including) CA root certificate.
    */
    */
-  const char *v_mem_key;
+  /* const */ char *v_mem_cert;
 
 
   /**
   /**
-   * the certificate loaded into memory (not a filename)
+   * the private key in PEM format loaded into memory (not a filename)
    */
    */
-  const char *v_mem_cert;
+  const char *v_mem_key;
 
 
   /**
   /**
    * the option passphrase phrase to decrypt the private key,
    * the option passphrase phrase to decrypt the private key,
@@ -656,10 +658,12 @@ union MHD_DaemonOptionValue
   enum MHD_TlsBackend tls;
   enum MHD_TlsBackend tls;
 
 
   /**
   /**
-   * Value for #MHD_D_O_TLS_KEY_CERT.
-   * the private key loaded into memory (not a filename)
+   * Value for #MHD_D_O_TLS_CERT_KEY.
+   * The X.509 certificates chain in PEM format loaded into memory (not a filename).
+   * The first certificate must be the server certificate, following by the chain of signing
+   * certificates up to (but not including) CA root certificate.
    */
    */
-  struct MHD_DaemonOptionValueTlsCert tls_key_cert;
+  struct MHD_DaemonOptionValueTlsCert tls_cert_key;
 
 
   /**
   /**
    * Value for #MHD_D_O_TLS_CLIENT_CA.
    * Value for #MHD_D_O_TLS_CLIENT_CA.
@@ -1023,20 +1027,22 @@ Works only when #MHD_D_OPTION_BIND_PORT() or #MHD_D_OPTION_BIND_SA() are used.
 /**
 /**
  * Provide TLS key and certificate data in-memory.
  * Provide TLS key and certificate data in-memory.
  * Works only if TLS mode is enabled.
  * Works only if TLS mode is enabled.
- * @param mem_key the private key loaded into memory (not a filename)
- * @param mem_cert the certificate loaded into memory (not a filename)
+ * @param mem_cert The X.509 certificates chain in PEM format loaded into memory (not a filename).
+ *   The first certificate must be the server certificate, following by the chain of signing
+ *   certificates up to (but not including) CA root certificate.
+ * @param mem_key the private key in PEM format loaded into memory (not a filename)
  * @param mem_pass the option passphrase phrase to decrypt the private key,
  * @param mem_pass the option passphrase phrase to decrypt the private key,
  *   could be NULL is private does not need a password
  *   could be NULL is private does not need a password
  * @return structure with the requested setting
  * @return structure with the requested setting
  */
  */
-#  define MHD_D_OPTION_TLS_KEY_CERT(mem_key,mem_cert,mem_pass) \
+#  define MHD_D_OPTION_TLS_CERT_KEY(mem_cert,mem_key,mem_pass) \
         MHD_NOWARN_COMPOUND_LITERALS_ \
         MHD_NOWARN_COMPOUND_LITERALS_ \
           (const struct MHD_DaemonOptionAndValue) \
           (const struct MHD_DaemonOptionAndValue) \
         { \
         { \
-          .opt = MHD_D_O_TLS_KEY_CERT,  \
-          .val.tls_key_cert.v_mem_key = (mem_key), \
-          .val.tls_key_cert.v_mem_cert = (mem_cert), \
-          .val.tls_key_cert.v_mem_pass = (mem_pass) \
+          .opt = MHD_D_O_TLS_CERT_KEY,  \
+          .val.tls_cert_key.v_mem_cert = (mem_cert), \
+          .val.tls_cert_key.v_mem_key = (mem_key), \
+          .val.tls_cert_key.v_mem_pass = (mem_pass) \
         } \
         } \
         MHD_RESTORE_WARN_COMPOUND_LITERALS_
         MHD_RESTORE_WARN_COMPOUND_LITERALS_
 /**
 /**
@@ -1740,25 +1746,27 @@ MHD_D_OPTION_TLS (
 /**
 /**
  * Provide TLS key and certificate data in-memory.
  * Provide TLS key and certificate data in-memory.
  * Works only if TLS mode is enabled.
  * Works only if TLS mode is enabled.
- * @param mem_key the private key loaded into memory (not a filename)
- * @param mem_cert the certificate loaded into memory (not a filename)
+ * @param mem_cert The X.509 certificates chain in PEM format loaded into memory (not a filename).
+ *   The first certificate must be the server certificate, following by the chain of signing
+ *   certificates up to (but not including) CA root certificate.
+ * @param mem_key the private key in PEM format loaded into memory (not a filename)
  * @param mem_pass the option passphrase phrase to decrypt the private key,
  * @param mem_pass the option passphrase phrase to decrypt the private key,
  *   could be NULL is private does not need a password
  *   could be NULL is private does not need a password
  * @return structure with the requested setting
  * @return structure with the requested setting
  */
  */
 static MHD_INLINE struct MHD_DaemonOptionAndValue
 static MHD_INLINE struct MHD_DaemonOptionAndValue
-MHD_D_OPTION_TLS_KEY_CERT (
+MHD_D_OPTION_TLS_CERT_KEY (
+  /* const */ char *mem_cert,
   const char *mem_key,
   const char *mem_key,
-  const char *mem_cert,
   const char *mem_pass
   const char *mem_pass
   )
   )
 {
 {
   struct MHD_DaemonOptionAndValue opt_val;
   struct MHD_DaemonOptionAndValue opt_val;
 
 
-  opt_val.opt = MHD_D_O_TLS_KEY_CERT;
-  opt_val.val.tls_key_cert.v_mem_key = mem_key;
-  opt_val.val.tls_key_cert.v_mem_cert = mem_cert;
-  opt_val.val.tls_key_cert.v_mem_pass = mem_pass;
+  opt_val.opt = MHD_D_O_TLS_CERT_KEY;
+  opt_val.val.tls_cert_key.v_mem_cert = mem_cert;
+  opt_val.val.tls_cert_key.v_mem_key = mem_key;
+  opt_val.val.tls_cert_key.v_mem_pass = mem_pass;
 
 
   return opt_val;
   return opt_val;
 }
 }

+ 34 - 17
src/include/microhttpd2_preamble.h.in

@@ -459,6 +459,7 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
   ,
   ,
   /**
   /**
    * Failed to allocate memory for the daemon resources.
    * Failed to allocate memory for the daemon resources.
+   * TODO: combine similar error codes for daemon
    */
    */
   MHD_SC_DAEMON_MALLOC_FAILURE = 30081
   MHD_SC_DAEMON_MALLOC_FAILURE = 30081
   ,
   ,
@@ -713,12 +714,6 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_TLS_DISABLED = 50000
   MHD_SC_TLS_DISABLED = 50000
   ,
   ,
-  /**
-   * The application attempted to setup TLS parameters before
-   * enabling TLS.
-   */
-  MHD_SC_TLS_BACKEND_UNINITIALIZED = 50003
-  ,
   /**
   /**
    * The selected TLS backend does not yet support this operation.
    * The selected TLS backend does not yet support this operation.
    */
    */
@@ -1286,6 +1281,11 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_LIB_INIT_GLOBAL_FAILED = 51000
   MHD_SC_LIB_INIT_GLOBAL_FAILED = 51000
   ,
   ,
+  /**
+   * Failed to initialise TLS context for the daemon
+   */
+  MHD_SC_DAEMON_TLS_INIT_FAILED = 51200
+  ,
   /**
   /**
    * Something wrong in the internal MHD logic.
    * Something wrong in the internal MHD logic.
    * This error should be never returned if MHD works as expected.
    * This error should be never returned if MHD works as expected.
@@ -1309,17 +1309,6 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 60001
   MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC = 60001
   ,
   ,
-  /**
-   * The application requested an unsupported TLS backend to be used.
-   */
-  MHD_SC_TLS_BACKEND_UNSUPPORTED = 60003
-  ,
-  /**
-   * The application requested a TLS cipher suite which is not
-   * supported by the selected backend.
-   */
-  MHD_SC_TLS_CIPHERS_INVALID = 60004
-  ,
   /**
   /**
    * MHD is closing a connection because the application
    * MHD is closing a connection because the application
    * logic to generate the response data failed.
    * logic to generate the response data failed.
@@ -1390,6 +1379,34 @@ enum MHD_FIXED_ENUM_MHD_SET_ MHD_StatusCode
    */
    */
   MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL = 60016
   MHD_SC_CONFIGURATION_CONN_LIMIT_TOO_SMALL = 60016
   ,
   ,
+  /**
+   * The application requested an unsupported TLS backend to be used.
+   */
+  MHD_SC_TLS_BACKEND_UNSUPPORTED = 60020
+  ,
+  /**
+   * The application attempted to setup TLS parameters before
+   * enabling TLS.
+   */
+  MHD_SC_TLS_BACKEND_UNINITIALIZED = 60021
+  ,
+  /**
+   * The application requested a TLS backend which cannot be used due
+   * to missing TLS dynamic library or backend initialisation problem.
+   */
+  MHD_SC_TLS_BACKEND_UNAVAILABLE = 60022
+  ,
+  /**
+   * Provided TLS certificate and/or private key are incorrect
+   */
+  MHD_SC_TLS_CONF_BAD_CERT = 60023
+  ,
+  /**
+   * The application requested a TLS cipher suite which is not
+   * supported by the selected backend.
+   */
+  MHD_SC_TLS_CIPHERS_INVALID = 60024
+  ,
   /**
   /**
    * The response header name has forbidden characters or token
    * The response header name has forbidden characters or token
    */
    */

+ 2 - 1
src/mhd2/Makefile.am

@@ -108,10 +108,11 @@ upgrade_files = \
 
 
 tls_common_files = \
 tls_common_files = \
   mhd_tls_choice.h \
   mhd_tls_choice.h \
-  mhd_tls_funcs.h \
+  mhd_tls_funcs.c           mhd_tls_funcs.h \
   tls_dh_params.h
   tls_dh_params.h
 
 
 tls_gnu_files = \
 tls_gnu_files = \
+  tls_gnu_tls_lib.h         tls_gnu_daemon_data.h     tls_gnu_conn_data.h \
   tls_gnu_funcs.c           tls_gnu_funcs.h
   tls_gnu_funcs.c           tls_gnu_funcs.h
 
 
 if HAVE_POST_PARSER
 if HAVE_POST_PARSER

+ 6 - 3
src/mhd2/daemon_create.c

@@ -81,9 +81,9 @@ MHD_daemon_create (MHD_RequestCallback req_cb,
   /* Any floating point and pointer members must be initialised manually here */
   /* Any floating point and pointer members must be initialised manually here */
 #ifndef HAVE_NULL_PTR_ALL_ZEROS
 #ifndef HAVE_NULL_PTR_ALL_ZEROS
   s->bind_sa.v_sa = NULL;
   s->bind_sa.v_sa = NULL;
-  s->tls_key_cert.v_mem_key = NULL;
-  s->tls_key_cert.v_mem_cert = NULL;
-  s->tls_key_cert.v_mem_pass = NULL;
+  s->tls_cert_key.v_mem_key = NULL;
+  s->tls_cert_key.v_mem_cert = NULL;
+  s->tls_cert_key.v_mem_pass = NULL;
   s->tls_client_ca = NULL;
   s->tls_client_ca = NULL;
   s->tls_psk_callback.v_psk_cb = NULL;
   s->tls_psk_callback.v_psk_cb = NULL;
   s->tls_psk_callback.v_psk_cb_cls = NULL;
   s->tls_psk_callback.v_psk_cb_cls = NULL;
@@ -98,6 +98,9 @@ MHD_daemon_create (MHD_RequestCallback req_cb,
   s->notify_stream.v_nsc = NULL;
   s->notify_stream.v_nsc = NULL;
   s->notify_stream.v_cls = NULL;
   s->notify_stream.v_cls = NULL;
   s->random_entropy.v_buf = NULL;
   s->random_entropy.v_buf = NULL;
+  s->tls_cert_key.v_mem_cert = NULL;
+  s->tls_cert_key.v_mem_key = NULL;
+  s->tls_cert_key.v_mem_pass = NULL;
 
 
   d->log_params.v_log_cb = NULL; /* optional */
   d->log_params.v_log_cb = NULL; /* optional */
 #endif /* !HAVE_NULL_PTR_ALL_ZEROS */
 #endif /* !HAVE_NULL_PTR_ALL_ZEROS */

+ 5 - 3
src/mhd2/daemon_options.h

@@ -94,10 +94,12 @@ struct DaemonOptions
 
 
 
 
   /**
   /**
-   * Value for #MHD_D_O_TLS_KEY_CERT.
-   * the private key loaded into memory (not a filename)
+   * Value for #MHD_D_O_TLS_CERT_KEY.
+   * The X.509 certificates chain in PEM format loaded into memory (not a filename).
+   * The first certificate must be the server certificate, following by the chain of signing
+   * certificates up to (but not including) CA root certificate.
    */
    */
-  struct MHD_DaemonOptionValueTlsCert tls_key_cert;
+  struct MHD_DaemonOptionValueTlsCert tls_cert_key;
 
 
 
 
   /**
   /**

+ 47 - 4
src/mhd2/daemon_set_options.c

@@ -86,10 +86,53 @@ MHD_daemon_set_options (
     case MHD_D_O_TLS:
     case MHD_D_O_TLS:
       settings->tls = option->val.tls;
       settings->tls = option->val.tls;
       continue;
       continue;
-    case MHD_D_O_TLS_KEY_CERT:
-      settings->tls_key_cert.v_mem_key = option->val.tls_key_cert.v_mem_key;
-      settings->tls_key_cert.v_mem_cert = option->val.tls_key_cert.v_mem_cert;
-      settings->tls_key_cert.v_mem_pass = option->val.tls_key_cert.v_mem_pass;
+    case MHD_D_O_TLS_CERT_KEY:
+      /* custom setter */
+      if ((NULL == option->val.tls_cert_key.v_mem_cert)
+          || (NULL == option->val.tls_cert_key.v_mem_key))
+        return MHD_SC_TLS_CONF_BAD_CERT;
+      else
+      {
+        size_t cert_size;
+        size_t key_size;
+        size_t pass_size;
+        cert_size = strlen (option->val.tls_cert_key.v_mem_cert);
+        key_size = strlen (option->val.tls_cert_key.v_mem_key);
+        if ((0 == cert_size)
+            || (0 == key_size))
+          return MHD_SC_TLS_CONF_BAD_CERT;
+        ++cert_size; /* Space for zero-termination */
+        ++key_size;  /* Space for zero-termination */
+        if (NULL != option->val.tls_cert_key.v_mem_pass)
+          pass_size = strlen (option->val.tls_cert_key.v_mem_cert);
+        else
+          pass_size = 0;
+        if (0 != pass_size)
+          ++pass_size; /* Space for zero-termination */
+        if (NULL != settings->tls_cert_key.v_mem_cert)
+          free (settings->tls_cert_key.v_mem_cert); // TODO: Support multiple certificates!!
+        settings->tls_cert_key.v_mem_cert = malloc (cert_size + key_size + pass_size);
+        if (NULL == settings->tls_cert_key.v_mem_cert)
+          return MHD_SC_DAEMON_MALLOC_FAILURE;
+        memcpy (settings->tls_cert_key.v_mem_cert,
+                option->val.tls_cert_key.v_mem_cert,
+                cert_size);
+        memcpy (settings->tls_cert_key.v_mem_cert + cert_size,
+                option->val.tls_cert_key.v_mem_key,
+                key_size);
+        settings->tls_cert_key.v_mem_key =
+          settings->tls_cert_key.v_mem_cert + cert_size;
+        if (0 != pass_size)
+        {
+          memcpy (settings->tls_cert_key.v_mem_cert + cert_size + key_size,
+                  option->val.tls_cert_key.v_mem_pass,
+                  pass_size);
+          settings->tls_cert_key.v_mem_pass =
+            settings->tls_cert_key.v_mem_cert + cert_size + key_size;
+        }
+        else
+          settings->tls_cert_key.v_mem_pass = NULL;
+      }
       continue;
       continue;
     case MHD_D_O_TLS_CLIENT_CA:
     case MHD_D_O_TLS_CLIENT_CA:
       settings->tls_client_ca = option->val.tls_client_ca;
       settings->tls_client_ca = option->val.tls_client_ca;

+ 108 - 15
src/mhd2/daemon_start.c

@@ -72,6 +72,10 @@
 #include "mhd_lib_init.h"
 #include "mhd_lib_init.h"
 #include "daemon_logger.h"
 #include "daemon_logger.h"
 
 
+#ifdef MHD_ENABLE_HTTPS
+#  include "mhd_tls_funcs.h"
+#endif
+
 #ifdef MHD_USE_THREADS
 #ifdef MHD_USE_THREADS
 #  include "mhd_itc.h"
 #  include "mhd_itc.h"
 #  include "mhd_threads.h"
 #  include "mhd_threads.h"
@@ -101,6 +105,8 @@ dsettings_release (struct DaemonOptions *s)
     mhd_socket_close (s->listen_socket);
     mhd_socket_close (s->listen_socket);
   if (NULL != s->bind_sa.v_sa)
   if (NULL != s->bind_sa.v_sa)
     free (s->bind_sa.v_sa);
     free (s->bind_sa.v_sa);
+  if (NULL != s->tls_cert_key.v_mem_cert)
+    free (s->tls_cert_key.v_mem_cert);
   free (s);
   free (s);
 }
 }
 
 
@@ -1437,6 +1443,88 @@ dauth_init (struct MHD_Daemon *restrict d,
 
 
 #endif
 #endif
 
 
+
+/**
+ * Initialise daemon TLS data
+ * @param d the daemon object
+ * @param s the user settings
+ * @return #MHD_SC_OK on success,
+ *         the error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) \
+  MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_init_tls (struct MHD_Daemon *restrict d,
+                 struct DaemonOptions *restrict s)
+{
+  mhd_StatusCodeInt ret;
+
+  mhd_assert (! d->dbg.tls_inited);
+#ifdef MHD_ENABLE_HTTPS
+  d->tls = NULL;
+#endif
+
+  if (MHD_TLS_BACKEND_NONE == s->tls)
+  {
+#ifndef NDEBUG
+    d->dbg.tls_inited = true;
+#endif
+    return MHD_SC_OK;
+  }
+#ifndef MHD_ENABLE_HTTPS
+  mhd_LOG_MSG (d, \
+               MHD_SC_TLS_DISABLED, \
+               "HTTPS is not supported by this MHD build");
+  return MHD_SC_TLS_DISABLED;
+#else  /* MHD_ENABLE_HTTPS */
+  if (1)
+  {
+    enum mhd_TlsBackendAvailable tls_avail;
+
+    tls_avail = mhd_tls_is_backend_available (s);
+    if (mhd_TLS_BACKEND_AVAIL_NOT_SUPPORTED == tls_avail)
+    {
+      mhd_LOG_MSG (d, \
+                   MHD_SC_TLS_BACKEND_UNSUPPORTED, \
+                   "The requested TLS backend is not supported " \
+                   "by this MHD build");
+      return MHD_SC_TLS_BACKEND_UNSUPPORTED;
+    }
+    else if (mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE == tls_avail)
+    {
+      mhd_LOG_MSG (d, \
+                   MHD_SC_TLS_BACKEND_UNAVAILABLE, \
+                   "The requested TLS backend is not available");
+      return MHD_SC_TLS_BACKEND_UNAVAILABLE;
+    }
+  }
+  ret = mhd_tls_daemon_init (d,
+                             &(d->tls),
+                             s);
+  mhd_assert ((MHD_SC_OK == ret) || (NULL == d->tls));
+  mhd_assert ((MHD_SC_OK != ret) || (NULL != d->tls));
+#ifndef NDEBUG
+  d->dbg.tls_inited = (MHD_SC_OK == ret);
+#endif
+  return (enum MHD_StatusCode) ret;
+#endif /* MHD_ENABLE_HTTPS */
+}
+
+
+/**
+ * Deinitialise daemon TLS data
+ * @param d the daemon object
+ */
+MHD_FN_PAR_NONNULL_ (1) static void
+daemon_deinit_tls (struct MHD_Daemon *restrict d)
+{
+  mhd_assert (d->dbg.tls_inited);
+#ifdef MHD_ENABLE_HTTPS
+  if (NULL != d->tls)
+    mhd_tls_daemon_deinit (d->tls);
+#endif
+}
+
+
 /**
 /**
  * Initialise large buffer tracking.
  * Initialise large buffer tracking.
  * @param d the daemon object
  * @param d the daemon object
@@ -2828,32 +2916,35 @@ daemon_start_internal (struct MHD_Daemon *restrict d,
   if (MHD_SC_OK != res)
   if (MHD_SC_OK != res)
     return res;
     return res;
 
 
+  mhd_assert (d->dbg.net_inited);
+  res = daemon_init_tls (d, s);
 
 
-  // TODO: Other init
-
-  res = daemon_init_threading_and_conn (d, s);
   if (MHD_SC_OK == res)
   if (MHD_SC_OK == res)
   {
   {
-    mhd_assert (d->dbg.net_inited);
-    mhd_assert (d->dbg.threading_inited);
-    mhd_assert (! mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
-
-    res = daemon_init_large_buf (d, s);
+    mhd_assert (d->dbg.tls_inited);
+    res = daemon_init_threading_and_conn (d, s);
     if (MHD_SC_OK == res)
     if (MHD_SC_OK == res)
     {
     {
-      res = daemon_start_threads (d);
+      mhd_assert (d->dbg.threading_inited);
+      mhd_assert (! mhd_D_TYPE_IS_INTERNAL_ONLY (d->threading.d_type));
+
+      res = daemon_init_large_buf (d, s);
       if (MHD_SC_OK == res)
       if (MHD_SC_OK == res)
       {
       {
-        return MHD_SC_OK;
-      }
+        res = daemon_start_threads (d);
+        if (MHD_SC_OK == res)
+        {
+          return MHD_SC_OK;
+        }
 
 
-      /* Below is a clean-up path */
-      daemon_deinit_large_buf (d);
+        /* Below is a clean-up path */
+        daemon_deinit_large_buf (d);
+      }
+      daemon_deinit_threading_and_conn (d);
     }
     }
-    daemon_deinit_threading_and_conn (d);
+    daemon_deinit_tls (d);
   }
   }
 
 
-
   daemon_deinit_net (d);
   daemon_deinit_net (d);
   mhd_assert (MHD_SC_OK != res);
   mhd_assert (MHD_SC_OK != res);
   return res;
   return res;
@@ -2911,6 +3002,8 @@ MHD_daemon_destroy (struct MHD_Daemon *daemon)
 
 
     daemon_deinit_large_buf (daemon);
     daemon_deinit_large_buf (daemon);
 
 
+    daemon_deinit_tls (daemon);
+
     daemon_deinit_net (daemon);
     daemon_deinit_net (daemon);
   }
   }
   daemon->state = mhd_DAEMON_STATE_STOPPED; /* Useful only for debugging */
   daemon->state = mhd_DAEMON_STATE_STOPPED; /* Useful only for debugging */

+ 21 - 0
src/mhd2/mhd_daemon.h

@@ -35,6 +35,10 @@
 
 
 #include "mhd_public_api.h"
 #include "mhd_public_api.h"
 
 
+#ifdef MHD_ENABLE_HTTPS
+#  include "mhd_tls_choice.h"
+#endif
+
 #ifdef MHD_USE_THREADS
 #ifdef MHD_USE_THREADS
 #  include "mhd_threads.h"
 #  include "mhd_threads.h"
 #  include "mhd_itc_types.h"
 #  include "mhd_itc_types.h"
@@ -873,6 +877,7 @@ struct mhd_daemon_debug
 {
 {
   bool net_inited;
   bool net_inited;
   bool net_deinited;
   bool net_deinited;
+  bool tls_inited;
   bool events_allocated;
   bool events_allocated;
   unsigned int num_events_elements;
   unsigned int num_events_elements;
   bool events_fully_inited;
   bool events_fully_inited;
@@ -913,6 +918,15 @@ struct MHD_Daemon
    */
    */
   struct mhd_DaemonNetwork net;
   struct mhd_DaemonNetwork net;
 
 
+#ifdef MHD_ENABLE_HTTPS
+  /**
+   * The pointer to the daemon TLS data.
+   * If set to non-NULL then HTTPS protocol is used, if set to NULL then
+   * plain HTTP protocol used.
+   */
+  struct mhd_DaemonTlsData *tls;
+#endif
+
 #ifdef MHD_USE_THREADS
 #ifdef MHD_USE_THREADS
   /* Threading data */
   /* Threading data */
 
 
@@ -1002,4 +1016,11 @@ struct MHD_Daemon
         (mhd_D_IS_USING_EPOLL (d) || \
         (mhd_D_IS_USING_EPOLL (d) || \
          (mhd_WM_INT_EXTERNAL_EVENTS_EDGE ==((d)->wmode_int)))
          (mhd_WM_INT_EXTERNAL_EVENTS_EDGE ==((d)->wmode_int)))
 
 
+#ifdef MHD_ENABLE_HTTPS
+#  define mhd_D_HAS_TLS(d) ((d->tls) ? (! 0) : (0))
+#else
+#  define mhd_D_HAS_TLS(d) (0)
+#endif
+
+
 #endif /* ! MHD_DAEMON_H */
 #endif /* ! MHD_DAEMON_H */

+ 49 - 0
src/mhd2/mhd_tls_funcs.c

@@ -0,0 +1,49 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/mhd_tls_funcs.c
+ * @brief  The TLS backend generic functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_sys_options.h"
+
+#include "mhd_tls_funcs.h"
+
+#include "mhd_assert.h"
+
+#include "mhd_public_api.h"
+#include "daemon_options.h"
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_
+enum mhd_TlsBackendAvailable
+mhd_tls_is_backend_available (struct DaemonOptions *s)
+{
+  mhd_assert (MHD_TLS_BACKEND_NONE != s->tls);
+  if (MHD_TLS_BACKEND_ANY == s->tls)
+    return mhd_tls_gnu_is_inited_fine ()
+           /* || mhd_tls_other_is_inited_fine() */;
+#ifdef MHD_USE_GNUTLS
+  if (MHD_TLS_BACKEND_GNUTLS == s->tls)
+    return mhd_tls_gnu_is_inited_fine ();
+#endif
+  return false;
+}

+ 63 - 0
src/mhd2/mhd_tls_funcs.h

@@ -30,6 +30,8 @@
 
 
 #include "mhd_sys_options.h"
 #include "mhd_sys_options.h"
 
 
+#include "sys_bool_type.h"
+
 #include "mhd_tls_choice.h"
 #include "mhd_tls_choice.h"
 #ifndef MHD_ENABLE_HTTPS
 #ifndef MHD_ENABLE_HTTPS
 #error This header should be used only if HTTPS is enabled
 #error This header should be used only if HTTPS is enabled
@@ -39,6 +41,12 @@
 #  include "tls_gnu_funcs.h"
 #  include "tls_gnu_funcs.h"
 #endif
 #endif
 
 
+#ifndef MHD_USE_GNUTLS
+#  define mhd_tls_gnu_is_inited_fine()   (0)
+#endif
+
+/* ** Global initialisation ** */
+
 /**
 /**
  * Perform one-time global initialisation of TLS backend
  * Perform one-time global initialisation of TLS backend
  */
  */
@@ -57,5 +65,60 @@
 #define mhd_tls_global_re_init()          \
 #define mhd_tls_global_re_init()          \
         mhd_MACRO_CONCAT3 (mhd_tls_,mhd_TLS_FUNC_NAME_ID,_global_re_init)()
         mhd_MACRO_CONCAT3 (mhd_tls_,mhd_TLS_FUNC_NAME_ID,_global_re_init)()
 
 
+/* ** Daemon initialisation ** */
+
+/**
+ * Set daemon TLS parameters
+ * @param d the daemon handle
+ * @param p_d_tls the pointer to variable to set the pointer to
+ *                the daemon's TLS settings (allocated by this function)
+ * @param s the daemon settings
+ * @return #MHD_SC_OK on success (p_d_tls set to the allocated settings),
+ *         error code otherwise
+ */
+#define mhd_tls_daemon_init(d,p_d_tls,s)        \
+        mhd_MACRO_CONCAT3 (mhd_tls_,mhd_TLS_FUNC_NAME_ID,_daemon_init)( \
+          (d),(p_d_tls),(s))
+
+/**
+ * De-initialise daemon TLS parameters (and free memory allocated for TLS
+ * settings)
+ * @param d_tls the pointer to  the daemon's TLS settings
+ */
+#define mhd_tls_daemon_deinit(d_tls)    \
+        mhd_MACRO_CONCAT3 (mhd_tls_,mhd_TLS_FUNC_NAME_ID,_daemon_deinit)( \
+          (d_tls))
+
+
+/**
+ * Result of TLS backend availablility check
+ */
+enum mhd_TlsBackendAvailable
+{
+  /**
+   * The TLS backend is available and can be used
+   */
+  mhd_TLS_BACKEND_AVAIL_OK = 0
+  ,
+  /**
+   * The TLS backend support is not enabled in this MHD build
+   */
+  mhd_TLS_BACKEND_AVAIL_NOT_SUPPORTED
+  ,
+  /**
+   * The TLS backend supported, but not available
+   */
+  mhd_TLS_BACKEND_AVAIL_NOT_AVAILABLE
+};
+
+/**
+ * Check whether the requested TLS backend is available
+ * @param s the daemon settings
+ * @return 'mhd_TLS_BACKEND_AVAIL_OK' if requested backend is available,
+ *         error code otherwise
+ */
+MHD_INTERNAL enum mhd_TlsBackendAvailable
+mhd_tls_is_backend_available (struct DaemonOptions *s)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_;
 
 
 #endif /* ! MHD_TLS_FUNCS_H */
 #endif /* ! MHD_TLS_FUNCS_H */

+ 53 - 0
src/mhd2/tls_dh_params.h

@@ -0,0 +1,53 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_dh_params.h
+ * @brief  The Diffie-Hellman parameters for TLS backends without RFC7919
+ *         support
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_DH_PARAMS_H
+#define MHD_TLS_DH_PARAMS_H 1
+
+#include "mhd_sys_options.h"
+
+/**
+ * The PEM encoded PKCS#3 Diffie-Hellman parameters.
+ *
+ * To be used only if TLS backend does not support RFC7919.
+ * Generated by GnuTLS "certtool --get-dh-params" command.
+ */
+static const char mhd_tls_dh_params_pkcs3[] =
+  "-----BEGIN DH PARAMETERS-----\n"
+  "MIIBjAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
+  "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
+  "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
+  "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
+  "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
+  "ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3\n"
+  "7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32\n"
+  "nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu\n"
+  "N///////////AgECAgIBFA==\n"
+  "-----END DH PARAMETERS-----\n";
+
+
+#endif /* ! MHD_TLS_DH_PARAMS_H */

+ 49 - 0
src/mhd2/tls_gnu_conn_data.h

@@ -0,0 +1,49 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_gnu_conn_data.h
+ * @brief  The definition of GnuTLS daemon-specific data structures
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_GNU_CONN_DATA_H
+#define MHD_TLS_GNU_CONN_DATA_H 1
+
+#include "mhd_sys_options.h"
+
+#ifndef MHD_USE_GNUTLS
+#error This header can be used only if GnuTLS is enabled
+#endif
+
+#include "tls_gnu_tls_lib.h"
+
+/**
+ * The structure with connection-specific GnuTLS data
+ */
+struct mhd_ConnTlsGnuData
+{
+  /**
+   * GnuTLS session data
+   */
+  gnutls_session_t sess;
+};
+
+#endif /* ! MHD_TLS_GNU_CONN_DATA_H */

+ 61 - 0
src/mhd2/tls_gnu_daemon_data.h

@@ -0,0 +1,61 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_gnu_daemon_data.h
+ * @brief  The definition of GnuTLS daemon-specific data structures
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_GNU_DAEMON_DATA_H
+#define MHD_TLS_GNU_DAEMON_DATA_H 1
+
+#include "mhd_sys_options.h"
+
+#ifndef MHD_USE_GNUTLS
+#error This header can be used only if GnuTLS is enabled
+#endif
+
+#include "tls_gnu_tls_lib.h"
+
+/**
+ * The structure with daemon-specific GnuTLS data
+ */
+struct mhd_DaemonTlsGnuData
+{
+  /**
+   * The credentials
+   */
+  gnutls_certificate_credentials_t cred;
+
+#ifdef mhd_TLS_GNU_DH_PARAMS_NEEDS_PKCS3
+  /**
+   * Diffie-Hellman parameters
+   */
+  gnutls_dh_params_t dh_params;
+#endif
+
+  /**
+   * TLS priorities cache
+   */
+  gnutls_priority_t pri_cache;
+};
+
+#endif /* ! MHD_TLS_GNU_DAEMON_DATA_H */

+ 345 - 1
src/mhd2/tls_gnu_funcs.c

@@ -29,10 +29,30 @@
 #include "sys_bool_type.h"
 #include "sys_bool_type.h"
 #include "sys_base_types.h"
 #include "sys_base_types.h"
 
 
-#include <gnutls/gnutls.h>
+#include <string.h>
 
 
+#include "mhd_str_types.h"
+#include "mhd_str_macros.h"
+#include "mhd_arr_num_elems.h"
+
+#include "compat_calloc.h"
+#include "sys_malloc.h"
+#include "mhd_assert.h"
+
+#include "tls_gnu_tls_lib.h"
+
+#include "tls_gnu_daemon_data.h"
 #include "tls_gnu_funcs.h"
 #include "tls_gnu_funcs.h"
 
 
+#include "daemon_options.h"
+
+#include "mhd_public_api.h"
+#include "daemon_logger.h"
+
+#ifdef  mhd_TLS_GNU_DH_PARAMS_NEEDS_PKCS3
+#  include "tls_dh_params.h"
+#endif
+
 struct mhd_DaemonTlsGnuData;    /* Forward declaration */
 struct mhd_DaemonTlsGnuData;    /* Forward declaration */
 
 
 struct mhd_ConnTlsGnuData;      /* Forward declaration */
 struct mhd_ConnTlsGnuData;      /* Forward declaration */
@@ -62,3 +82,327 @@ mhd_tls_gnu_global_deinit (void)
     gnutls_global_deinit ();
     gnutls_global_deinit ();
   gnutls_lib_inited = false;
   gnutls_lib_inited = false;
 }
 }
+
+
+MHD_INTERNAL bool
+mhd_tls_gnu_is_inited_fine (void)
+{
+  return gnutls_lib_inited;
+}
+
+
+/* ** Daemon initialisation ** */
+
+/**
+ * Check application-provided daemon TLS settings
+ * @param d the daemon handle
+ * @param s the application-provided settings
+ * @return #MHD_SC_OK on success,
+ *         error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+check_app_tls_sessings (struct MHD_Daemon *restrict d,
+                        struct DaemonOptions *restrict s)
+{
+  mhd_assert (MHD_TLS_BACKEND_NONE == s->tls);
+  mhd_assert ((MHD_TLS_BACKEND_GNUTLS == s->tls) || \
+              (MHD_TLS_BACKEND_ANY == s->tls));
+  if (NULL == s->tls_cert_key.v_mem_cert)
+  {
+    mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
+                 "No valid TLS certificate is provided");
+    return MHD_SC_TLS_CONF_BAD_CERT;
+  }
+  mhd_assert (NULL != s->tls_cert_key.v_mem_key);
+
+  return MHD_SC_OK;
+}
+
+
+/**
+ * Initialise daemon TLS Diffie-Hellman parameters.
+ *
+ * This function initialise Diffie-Hellman parameters for the daemon based
+ * on GnuTLS recommended defaults.
+ * With modern GnuTLS versions this function is no-op and always succeed.
+ *
+ * This function does not put any messages to the log.
+ * @param d_tls the daemon TLS data
+ * @return 'true' if succeed,
+ *         'false' if failed
+ */
+static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool
+daemon_init_dh_data (struct mhd_DaemonTlsGnuData *restrict d_tls)
+{
+#if defined(mhd_TLS_GNU_DH_PARAMS_USE_KNOWN)
+  /* Rely on reasonable TLS defaults set in the TLS library.
+     Modern GnuTLS versions relies completely on RFC 7919 and do not need
+     this function therefore do not bother implementing special
+     application-defined settings just for limited number of GnuTLS
+     versions (>= 3.5.6 && < 3.6.0). */
+  return (GNUTLS_E_SUCCESS ==
+          gnutls_certificate_set_known_dh_params (d_tls->cred,
+                                                  GNUTLS_SEC_PARAM_MEDIUM));
+#elif defined(mhd_TLS_GNU_DH_PARAMS_NEEDS_PKCS3)
+  gnutls_datum_t dh_data;
+  if (GNUTLS_E_SUCCESS  !=
+      gnutls_dh_params_init (&(d_tls->dh_params)))
+    return false;
+
+  dh_data.data = mhd_DROP_CONST (mhd_tls_dh_params_pkcs3);
+  dh_data.size = sizeof (mhd_tls_dh_params_pkcs3);
+  if (GNUTLS_E_SUCCESS ==
+      gnutls_dh_params_import_pkcs3 (d_tls->dh_params,
+                                     &dh_data,
+                                     GNUTLS_X509_FMT_PEM))
+  {
+    gnutls_certificate_set_dh_params (d_tls->cred,
+                                      d_tls->dh_params);
+    return true; /* success exit point */
+  }
+  /* Below is a clean-up code path */
+  gnutls_dh_params_deinit (d_tls->dh_params);
+  return false;
+#else
+  (void) d_tls; /* Mute compiler warning */
+  return true;
+#endif
+}
+
+
+/**
+ * De-initialise daemon TLS Diffie-Hellman parameters.
+ * @param d_tls the daemon TLS data
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+daemon_deinit_dh_data (struct mhd_DaemonTlsGnuData *restrict d_tls)
+{
+#if defined(mhd_TLS_GNU_DH_PARAMS_NEEDS_PKCS3)
+  mhd_assert (NULL != d_tls->dh_params);
+  gnutls_dh_params_deinit (d_tls->dh_params);
+#else
+  (void) d_tls; /* Mute compiler warning */
+#endif
+}
+
+
+/**
+ * Set daemon TLS credentials (and Diffie-Hellman parameters).
+ * This function puts error messages to the log if needed.
+ * @param d the daemon handle
+ * @param d_tls the daemon TLS settings
+ * @param s the application-provided settings
+ * @return #MHD_SC_OK on success,
+ *         error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_init_credentials (struct MHD_Daemon *restrict d,
+                         struct mhd_DaemonTlsGnuData *restrict d_tls,
+                         struct DaemonOptions *restrict s)
+{
+  enum MHD_StatusCode res;
+  size_t cert_len;
+  size_t key_len;
+
+  if (GNUTLS_E_SUCCESS !=
+      gnutls_certificate_allocate_credentials (&(d_tls->cred)))
+  {
+    mhd_LOG_MSG (d, MHD_SC_DAEMON_TLS_INIT_FAILED, \
+                 "Failed to initialise TLS credentials for the daemon");
+    return MHD_SC_DAEMON_TLS_INIT_FAILED;
+  }
+
+  // TODO: Support multiple certificates
+  cert_len = strlen (s->tls_cert_key.v_mem_cert) + 1; // TODO: Reuse calculated length
+  key_len = strlen (s->tls_cert_key.v_mem_key) + 1;   // TODO: Reuse calculated length
+
+  if (((unsigned int) cert_len != cert_len)
+      || ((unsigned int) key_len != key_len))
+    res = MHD_SC_TLS_CONF_BAD_CERT; /* Very unlikely, do not waste space on special message */
+  else
+  {
+    gnutls_datum_t cert_data;
+    gnutls_datum_t key_data;
+
+    cert_data.data = mhd_DROP_CONST (s->tls_cert_key.v_mem_cert);
+    cert_data.size = (unsigned int) cert_len;
+    key_data.data = mhd_DROP_CONST (s->tls_cert_key.v_mem_key);
+    key_data.size = (unsigned int) key_len;
+    if (0 >
+        gnutls_certificate_set_x509_key_mem2 (d_tls->cred,
+                                              &cert_data,
+                                              &key_data,
+                                              GNUTLS_X509_FMT_PEM,
+                                              s->tls_cert_key.v_mem_pass,
+                                              0))
+    {
+      mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \
+                   "Failed to set the provided TLS certificate");
+      res = MHD_SC_TLS_CONF_BAD_CERT;
+    }
+    else
+    {
+      if (! daemon_init_dh_data (d_tls))
+      {
+        mhd_LOG_MSG (d, MHD_SC_DAEMON_TLS_INIT_FAILED, \
+                     "Failed to initialise Diffie-Hellman parameters " \
+                     "for the daemon");
+        res = MHD_SC_DAEMON_TLS_INIT_FAILED;
+      }
+      else
+        return MHD_SC_OK;
+    }
+  }
+
+  gnutls_certificate_free_credentials (d_tls->cred);
+  mhd_assert (MHD_SC_OK != res);
+  return res; /* Failure exit point */
+}
+
+
+/**
+ * Free daemon fully allocated credentials (and Diffie-Hellman parameters).
+ * @param d_tls the daemon TLS settings
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+daemon_deinit_credentials (struct mhd_DaemonTlsGnuData *restrict d_tls)
+{
+  mhd_assert (NULL != d_tls->cred);
+  /* To avoid dangling pointer to DH data in the credentials,
+     free credentials first and then free DH data. */
+  gnutls_certificate_free_credentials (d_tls->cred);
+  daemon_deinit_dh_data (d_tls);
+}
+
+
+static const struct MHD_StringNullable tlsgnulib_base_priorities[] = {
+  {0, NULL} /* Replaced with app-defined name */
+  ,
+#ifdef mhd_TLS_GNU_SUPPORTS_MULTI_KEYWORDS_PRIORITY
+  mhd_MSTR_INIT ("@LIBMICROHTTPD,@SYSTEM")
+#else
+  mhd_MSTR_INIT ("@LIBMICROHTTPD")
+  ,
+  mhd_MSTR_INIT ("@SYSTEM")
+#endif
+  ,
+  {0, NULL}
+  ,
+  mhd_MSTR_INIT ("NORMAL")
+};
+
+/**
+ * Initialise GnuTLS priorities cache
+ * @param d the daemon handle
+ * @param d_tls the daemon TLS settings
+ * @param s the application-provided settings
+ * @return #MHD_SC_OK on success,
+ *         error code otherwise
+ */
+static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode
+daemon_init_priorities_cache (struct MHD_Daemon *restrict d,
+                              struct mhd_DaemonTlsGnuData *restrict d_tls,
+                              struct DaemonOptions *restrict s)
+{
+  size_t i;
+
+  (void) s; // TODO: support app-defined name for TLS backend profile
+
+  for (i = 0; i < mhd_ARR_NUM_ELEMS (tlsgnulib_base_priorities); ++i)
+  {
+    if (0 == i)
+      continue; // TODO: support app-defined name for TLS backend profile
+#if ! defined(mhd_TLS_GNU_TREATS_NULL_AS_DEF_PRIORITY)
+    if (NULL == tlsgnulib_base_priorities[i].cstr)
+    {
+      /* GnuTLS default priorities */
+#  if defined(mhd_TLS_GNU_NULL_PRIO_CACHE_MEANS_DEF_PRIORITY)
+      d_tls->pri_cache = NULL;
+      break;
+#  else
+      continue; /* "default" priorities cannot be used */
+#  endif
+    }
+#endif /* ! mhd_TLS_GNU_TREATS_NULL_AS_DEF_PRIORITY */
+    if (GNUTLS_E_SUCCESS ==
+        gnutls_priority_init (&(d_tls->pri_cache),
+                              tlsgnulib_base_priorities[i].cstr,
+                              NULL))
+      break;
+  }
+
+  if (i < mhd_ARR_NUM_ELEMS (tlsgnulib_base_priorities))
+    return MHD_SC_OK; /* Success exit point */
+
+  mhd_LOG_MSG (d, MHD_SC_DAEMON_TLS_INIT_FAILED, \
+               "Failed to initialise TLS priorities cache");
+  return MHD_SC_DAEMON_TLS_INIT_FAILED;
+}
+
+
+/**
+ * De-initialise priorities cache
+ * @param d_tls the daemon TLS settings
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+daemon_deinit_priorities_cache (struct mhd_DaemonTlsGnuData *restrict d_tls)
+{
+#if ! defined(mhd_TLS_GNU_NULL_PRIO_CACHE_MEANS_DEF_PRIORITY)
+  mhd_assert (NULL != d_tls->pri_cache);
+#else
+  if (NULL != d_tls->pri_cache)
+#endif
+  gnutls_priority_deinit (d_tls->pri_cache);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (2) mhd_StatusCodeInt
+mhd_tls_gnu_daemon_init (struct MHD_Daemon *restrict d,
+                         struct mhd_DaemonTlsGnuData **restrict p_d_tls,
+                         struct DaemonOptions *restrict s)
+{
+  mhd_StatusCodeInt res;
+  struct mhd_DaemonTlsGnuData *restrict d_tls;
+
+  res = check_app_tls_sessings (d, s);
+  if (MHD_SC_OK != res)
+    return res;
+
+  d_tls = (struct mhd_DaemonTlsGnuData *)
+          mhd_calloc (1, sizeof (struct mhd_DaemonTlsGnuData));
+  *p_d_tls = d_tls;
+  if (NULL == d_tls)
+    return MHD_SC_DAEMON_MALLOC_FAILURE;
+
+  res = daemon_init_credentials (d,
+                                 d_tls,
+                                 s);
+  if (MHD_SC_OK == res)
+  {
+    res = daemon_init_priorities_cache (d,
+                                        d_tls,
+                                        s);
+    if (MHD_SC_OK == res)
+      return MHD_SC_OK; /* Success exit point */
+
+    /* Below is a clean-up code path */
+    daemon_deinit_credentials (d_tls);
+  }
+
+  free (d_tls);
+  *p_d_tls = NULL;
+  mhd_assert (MHD_SC_OK != res);
+  return res;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_INOUT_ (1) void
+mhd_tls_gnu_daemon_deinit (struct mhd_DaemonTlsGnuData *restrict d_tls)
+{
+  mhd_assert (NULL != d_tls);
+  daemon_deinit_priorities_cache (d_tls);
+  daemon_deinit_credentials (d_tls);
+  free (d_tls);
+}

+ 38 - 0
src/mhd2/tls_gnu_funcs.h

@@ -33,6 +33,8 @@
 #error This header can be used only if GnuTLS is enabled
 #error This header can be used only if GnuTLS is enabled
 #endif
 #endif
 
 
+#include "mhd_status_code_int.h"
+
 /**
 /**
  * The structure with daemon-specific GnuTLS data
  * The structure with daemon-specific GnuTLS data
  */
  */
@@ -64,4 +66,40 @@ mhd_tls_gnu_global_init (void);
 MHD_INTERNAL void
 MHD_INTERNAL void
 mhd_tls_gnu_global_deinit (void);
 mhd_tls_gnu_global_deinit (void);
 
 
+/**
+ * Check whether GnuTLS backend was successfully initialised globally
+ */
+MHD_INTERNAL bool
+mhd_tls_gnu_is_inited_fine (void);
+
+
+/* ** Daemon initialisation ** */
+
+struct MHD_Daemon;      /* Forward declaration */
+struct DaemonOptions;   /* Forward declaration */
+
+/**
+ * Set daemon TLS parameters
+ * @param d the daemon handle
+ * @param p_d_tls the pointer to variable to set the pointer to
+ *                the daemon's TLS settings (allocated by this function)
+ * @param s the daemon settings
+ * @return #MHD_SC_OK on success (p_d_tls set to the allocated settings),
+ *         error code otherwise
+ */
+MHD_INTERNAL mhd_StatusCodeInt
+mhd_tls_gnu_daemon_init (struct MHD_Daemon *restrict d,
+                         struct mhd_DaemonTlsGnuData **restrict p_d_tls,
+                         struct DaemonOptions *restrict s)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (2);
+
+/**
+ * De-initialise daemon TLS parameters (and free memory allocated for TLS
+ * settings)
+ * @param d_tls the pointer to  the daemon's TLS settings
+ */
+MHD_INTERNAL void
+mhd_tls_gnu_daemon_deinit (struct mhd_DaemonTlsGnuData *restrict d_tls)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
 #endif /* ! MHD_TLS_GNU_FUNCS_H */
 #endif /* ! MHD_TLS_GNU_FUNCS_H */

+ 103 - 0
src/mhd2/tls_gnu_tls_lib.h

@@ -0,0 +1,103 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_gnu_tls_lib.h
+ * @brief  The wrapper for GnuTLS header
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_GNU_TLS_LIB_H
+#define MHD_TLS_GNU_TLS_LIB_H 1
+
+#include "mhd_sys_options.h"
+
+#ifndef MHD_USE_GNUTLS
+#error This header can be used only if GnuTLS is enabled
+#endif
+
+#include <gnutls/gnutls.h>
+
+#ifndef GNUTLS_VERSION_NUMBER
+#error GNUTLS_VERSION_NUMBER is not defined
+#endif
+
+#if GNUTLS_VERSION_NUMBER >= 0x030600
+/**
+ * Indicate that RC7919 defaults are used
+ */
+#  define mhd_TLS_GNU_HAS_RFC7919_DEFS       1
+#endif
+
+#ifndef mhd_TLS_GNU_HAS_RFC7919_DEFS
+#  if GNUTLS_VERSION_NUMBER >= 0x030506
+/**
+ * Use gnutls_certificate_set_known_dh_params() function to set DH parameters
+ */
+#    define mhd_TLS_GNU_DH_PARAMS_USE_KNOWN       1
+#  else
+/**
+ * TLS backend needs encoded Diffie-Hellman parameters
+ */
+#    define mhd_TLS_GNU_DH_PARAMS_NEEDS_PKCS3    1
+#  endif
+#endif
+
+#if GNUTLS_VERSION_NUMBER >= 0x020104
+/**
+ * Defined if gnutls_set_default_priority() function is available
+ */
+#  define mhd_TLS_GNU_HAS_SET_DEF_PRIORITY      1
+#endif
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+/**
+ * Defined if NULL is treated as "default priorities" when used as "priorities"
+ * argument for gnutls_priority_init() and gnutls_priority_init2()
+ */
+#  define mhd_TLS_GNU_TREATS_NULL_AS_DEF_PRIORITY        1
+#endif
+
+#if ! defined(mhd_TLS_GNU_TREATS_NULL_AS_DEF_PRIORITY) \
+  && defined(mhd_TLS_GNU_HAS_SET_DEF_PRIORITY)
+/**
+ * Defined if NULL in priorities cache is treated as indication that default
+ * priorities must used for connection / session
+ */
+#  define mhd_TLS_GNU_NULL_PRIO_CACHE_MEANS_DEF_PRIORITY        1
+#endif
+
+#if GNUTLS_VERSION_NUMBER >= 0x030603
+/**
+ * Defined if gnutls_priority_init2() function and the flag
+ * GNUTLS_PRIORITY_INIT_DEF_APPEND are available
+ */
+#  define mhd_TLS_GNU_HAS_PRIORITY_INIT2        1
+#endif
+
+#if GNUTLS_VERSION_NUMBER >= 0x030501
+/**
+ * Defined if gnutls_priority_init{,2}() functions support "@KEYWORD1,@KEYWORD2"
+ * to as fallback values.
+ */
+#  define mhd_TLS_GNU_SUPPORTS_MULTI_KEYWORDS_PRIORITY  1
+#endif
+
+#endif /* ! MHD_TLS_GNU_TLS_LIB_H */