Sfoglia il codice sorgente

integrate TLS PSK patch from Tal Moaz (plus documentation, plus style and bugfixes

Christian Grothoff 7 anni fa
parent
commit
2c47a23dec
7 ha cambiato i file con 187 aggiunte e 10 eliminazioni
  1. 1 0
      AUTHORS
  2. 4 0
      ChangeLog
  3. 10 0
      doc/libmicrohttpd.texi
  4. 33 5
      src/include/microhttpd.h
  5. 35 0
      src/include/microhttpd2.h
  6. 89 5
      src/microhttpd/daemon.c
  7. 15 0
      src/microhttpd/internal.h

+ 1 - 0
AUTHORS

@@ -58,6 +58,7 @@ Louis Benoit <[email protected]>
 Flavio Coelin <[email protected]>
 Flavio Coelin <[email protected]>
 Silvio Clecio <[email protected]>
 Silvio Clecio <[email protected]>
 Robert D Kosisko <[email protected]>
 Robert D Kosisko <[email protected]>
+Tal Moaz <[email protected]>
 
 
 Documentation contributions also came from:
 Documentation contributions also came from:
 Marco Maggi <[email protected]>
 Marco Maggi <[email protected]>

+ 4 - 0
ChangeLog

@@ -1,3 +1,7 @@
+Sat Jul 14 11:42:15 CEST 2018
+	Add MHD_OPTION_GNUTLS_PSK_CRED_HANDLER to allow use of PSK with
+	TLS connections. -CG/TM
+
 Sat Jul 14 11:03:37 CEST 2018
 Sat Jul 14 11:03:37 CEST 2018
 	Integrate patch for checking digest authentication based on
 	Integrate patch for checking digest authentication based on
 	a digest, allowing servers to store passwords only hashed.
 	a digest, allowing servers to store passwords only hashed.

+ 10 - 0
doc/libmicrohttpd.texi

@@ -869,6 +869,16 @@ information provided.  The callback is expected to access the SNI data
 using gnutls_server_name_get().  Using this option requires GnuTLS 3.0
 using gnutls_server_name_get().  Using this option requires GnuTLS 3.0
 or higher.
 or higher.
 
 
+@item MHD_OPTION_GNUTLS_PSK_CRED_HANDLER
+@cindex SSL
+@cindex TLS
+@cindex PSK
+Use pre-shared key for TLS credentials.
+Pass a pointer to callback of type 
+@code{MHD_PskServerCredentialsCallback} and a closure.
+The function will be called to 
+retrieve the shared key for a given username.
+
 @item MHD_OPTION_DIGEST_AUTH_RANDOM
 @item MHD_OPTION_DIGEST_AUTH_RANDOM
 @cindex digest auth
 @cindex digest auth
 @cindex random
 @cindex random

+ 33 - 5
src/include/microhttpd.h

@@ -1166,6 +1166,25 @@ typedef void
                    va_list ap);
                    va_list ap);
 
 
 
 
+/**
+ * Function called to lookup the pre shared key (@a psk) for a given
+ * HTTP connection based on the @a username.
+ *
+ * @param cls closure
+ * @param connection the HTTPS connection
+ * @param username the user name claimed by the other side
+ * @param psk[out] to be set to the pre-shared-key; should be allocated with malloc(),
+ *                 will be freed by MHD
+ * @param psk_size[out] to be set to the number of bytes in @a psk
+ * @return 0 on success, -1 on errors 
+ */
+typedef int
+(*MHD_PskServerCredentialsCallback)(void *cls,
+				    const struct MHD_Connection *connection,
+				    const char *username,
+				    void **psk,
+				    size_t *psk_size);
+
 /**
 /**
  * @brief MHD options.
  * @brief MHD options.
  *
  *
@@ -1489,7 +1508,15 @@ enum MHD_OPTION
    * testing clients against MHD, and 0 in production.  This option
    * testing clients against MHD, and 0 in production.  This option
    * should be followed by an `int` argument.
    * should be followed by an `int` argument.
    */
    */
-  MHD_OPTION_STRICT_FOR_CLIENT = 29
+  MHD_OPTION_STRICT_FOR_CLIENT = 29,
+
+  /**
+   * This should be a pointer to callback of type 
+   * gnutls_psk_server_credentials_function that will be given to
+   * gnutls_psk_set_server_credentials_function. It is used to
+   * retrieve the shared key for a given username.
+   */
+  MHD_OPTION_GNUTLS_PSK_CRED_HANDLER = 30
 };
 };
 
 
 
 
@@ -3150,10 +3177,11 @@ MHD_free (void *ptr);
  */
  */
 _MHD_EXTERN int
 _MHD_EXTERN int
 MHD_digest_auth_check (struct MHD_Connection *connection,
 MHD_digest_auth_check (struct MHD_Connection *connection,
-				const char *realm,
-				const char *username,
-				const char *password,
-				unsigned int nonce_timeout);
+		       const char *realm,
+		       const char *username,
+		       const char *password,
+		       unsigned int nonce_timeout);
+
 
 
 /**
 /**
  * Authenticates the authorization header sent by the client
  * Authenticates the authorization header sent by the client

+ 35 - 0
src/include/microhttpd2.h

@@ -2180,6 +2180,41 @@ MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon,
   MHD_NONNULL(1);
   MHD_NONNULL(1);
 
 
 
 
+/**
+ * Function called to lookup the pre shared key (@a psk) for a given
+ * HTTP connection based on the @a username.
+ *
+ * @param cls closure
+ * @param connection the HTTPS connection
+ * @param username the user name claimed by the other side
+ * @param psk[out] to be set to the pre-shared-key; should be allocated with malloc(),
+ *                 will be freed by MHD
+ * @param psk_size[out] to be set to the number of bytes in @a psk
+ * @return 0 on success, -1 on errors 
+ */
+typedef int
+(*MHD_PskServerCredentialsCallback)(void *cls,
+				    const struct MHD_Connection *connection,
+				    const char *username,
+				    void **psk,
+				    size_t *psk_size);
+
+
+/**
+ * Configure PSK to use for the TLS key exchange.
+ *
+ * @param daemon daemon to configure tls for
+ * @param psk_cb function to call to obtain pre-shared key
+ * @param psk_cb_cls closure for @a psk_cb
+ * @return #MHD_SC_OK upon success; TODO: define failure modes
+ */
+_MHD_EXTERN enum MHD_StatusCode
+MHD_daemon_set_tls_psk_callback (struct MHD_Daemon *daemon,
+				 MHD_PskServerCredentialsCallback psk_cb,
+				 void *psk_cb_cls)
+  MHD_NONNULL(1);
+
+
 /**
 /**
  * Memory pointer for the certificate (ca.pem) to be used by the
  * Memory pointer for the certificate (ca.pem) to be used by the
  * HTTPS daemon for client authentification.
  * HTTPS daemon for client authentification.

+ 89 - 5
src/microhttpd/daemon.c

@@ -565,7 +565,6 @@ MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
   return -1;
   return -1;
 }
 }
 
 
-
 /**
 /**
  * Initialize security aspects of the HTTPS daemon
  * Initialize security aspects of the HTTPS daemon
  *
  *
@@ -582,6 +581,11 @@ MHD_TLS_init (struct MHD_Daemon *daemon)
           gnutls_certificate_allocate_credentials (&daemon->x509_cred))
           gnutls_certificate_allocate_credentials (&daemon->x509_cred))
         return GNUTLS_E_MEMORY_ERROR;
         return GNUTLS_E_MEMORY_ERROR;
       return MHD_init_daemon_certificate (daemon);
       return MHD_init_daemon_certificate (daemon);
+    case GNUTLS_CRD_PSK:
+      if (0 != 
+          gnutls_psk_allocate_server_credentials (&daemon->psk_cred))
+        return GNUTLS_E_MEMORY_ERROR;
+      return 0;
     default:
     default:
 #ifdef HAVE_MESSAGES
 #ifdef HAVE_MESSAGES
       MHD_DLOG (daemon,
       MHD_DLOG (daemon,
@@ -2137,6 +2141,67 @@ MHD_tls_push_func_(gnutls_transport_ptr_t trnsp,
 #endif /* MHD_TLSLIB_DONT_SUPPRESS_SIGPIPE */
 #endif /* MHD_TLSLIB_DONT_SUPPRESS_SIGPIPE */
 #endif /* HTTPS_SUPPORT */
 #endif /* HTTPS_SUPPORT */
 
 
+
+/**
+ * Function called by GNUtls to obtain the PSK for a given session.
+ * 
+ * @param session the session to lookup PSK for
+ * @param username username to lookup PSK for
+ * @param key[out] where to write PSK
+ * @return 0 on success, -1 on error
+ */
+static int
+psk_gnutls_adapter (gnutls_session_t session,
+		    const char *username,
+		    gnutls_datum_t *key)
+{
+  struct MHD_Connection *connection;
+  struct MHD_Daemon *daemon;
+  void *app_psk;
+  size_t app_psk_size;
+
+  connection = gnutls_session_get_ptr (session);
+  if (NULL == connection)
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+	      _("Internal server error. This should be impossible.\n"));
+#endif
+    return -1;
+  }
+  daemon = connection->daemon;
+  if (NULL == daemon->cred_callback)
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+	      _("PSK not supported by this server.\n"));
+#endif
+    return -1;
+  }
+  if (0 != daemon->cred_callback (daemon->cred_callback_cls,
+				  connection,
+				  username,
+				  &app_psk,
+				  &app_psk_size))
+    return -1;
+  if (NULL == (key->data = gnutls_malloc (app_psk_size)))
+    {
+#ifdef HAVE_MESSAGES
+      MHD_DLOG (daemon,
+		_("PSK authentication failed: gnutls_malloc failed to allocate memory\n"));
+#endif
+      free (app_psk);
+      return -1;
+    }
+  key->size = app_psk_size;
+  memcpy (key->data,
+	  app_psk,
+	  app_psk_size);
+  free (app_psk);
+  return 0;
+}
+
+
 /**
 /**
  * Add another client connection to the set of connections
  * Add another client connection to the set of connections
  * managed by MHD.  This API is usually not needed (since
  * managed by MHD.  This API is usually not needed (since
@@ -2372,6 +2437,12 @@ internal_add_connection (struct MHD_Daemon *daemon,
           gnutls_credentials_set (connection->tls_session,
           gnutls_credentials_set (connection->tls_session,
 				  GNUTLS_CRD_CERTIFICATE,
 				  GNUTLS_CRD_CERTIFICATE,
 				  daemon->x509_cred);
 				  daemon->x509_cred);
+        case GNUTLS_CRD_PSK:
+          gnutls_credentials_set (connection->tls_session,
+                                  GNUTLS_CRD_PSK,
+                                  daemon->psk_cred);
+          gnutls_psk_set_server_credentials_function (daemon->psk_cred,
+                                                      &psk_gnutls_adapter);
           break;
           break;
         default:
         default:
 #ifdef HAVE_MESSAGES
 #ifdef HAVE_MESSAGES
@@ -2392,12 +2463,15 @@ internal_add_connection (struct MHD_Daemon *daemon,
  	  return MHD_NO;
  	  return MHD_NO;
         }
         }
 #if (GNUTLS_VERSION_NUMBER+0 >= 0x030109) && !defined(_WIN64)
 #if (GNUTLS_VERSION_NUMBER+0 >= 0x030109) && !defined(_WIN64)
-      gnutls_transport_set_int (connection->tls_session, (int)(client_socket));
+      gnutls_transport_set_int (connection->tls_session,
+				(int)(client_socket));
 #else  /* GnuTLS before 3.1.9 or Win x64 */
 #else  /* GnuTLS before 3.1.9 or Win x64 */
-      gnutls_transport_set_ptr (connection->tls_session, (gnutls_transport_ptr_t)(intptr_t)(client_socket));
+      gnutls_transport_set_ptr (connection->tls_session,
+				(gnutls_transport_ptr_t)(intptr_t)(client_socket));
 #endif /* GnuTLS before 3.1.9 */
 #endif /* GnuTLS before 3.1.9 */
 #ifdef MHD_TLSLIB_NEED_PUSH_FUNC
 #ifdef MHD_TLSLIB_NEED_PUSH_FUNC
-      gnutls_transport_set_push_function (connection->tls_session, MHD_tls_push_func_);
+      gnutls_transport_set_push_function (connection->tls_session,
+					  MHD_tls_push_func_);
 #endif /* MHD_TLSLIB_NEED_PUSH_FUNC */
 #endif /* MHD_TLSLIB_NEED_PUSH_FUNC */
       if (daemon->https_mem_trust)
       if (daemon->https_mem_trust)
 	  gnutls_certificate_server_set_request (connection->tls_session,
 	  gnutls_certificate_server_set_request (connection->tls_session,
@@ -2407,7 +2481,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
       goto cleanup;
       goto cleanup;
 #endif /* ! HTTPS_SUPPORT */
 #endif /* ! HTTPS_SUPPORT */
     }
     }
-
+  gnutls_session_set_ptr (connection->tls_session,
+			  connection);
 
 
   MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
   MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
   /* Firm check under lock. */
   /* Firm check under lock. */
@@ -5070,6 +5145,7 @@ parse_options_va (struct MHD_Daemon *daemon,
 		case MHD_OPTION_URI_LOG_CALLBACK:
 		case MHD_OPTION_URI_LOG_CALLBACK:
 		case MHD_OPTION_EXTERNAL_LOGGER:
 		case MHD_OPTION_EXTERNAL_LOGGER:
 		case MHD_OPTION_UNESCAPE_CALLBACK:
 		case MHD_OPTION_UNESCAPE_CALLBACK:
+		case MHD_OPTION_GNUTLS_PSK_CRED_HANDLER:
 		  if (MHD_YES != parse_options (daemon,
 		  if (MHD_YES != parse_options (daemon,
 						servaddr,
 						servaddr,
 						opt,
 						opt,
@@ -5100,6 +5176,12 @@ parse_options_va (struct MHD_Daemon *daemon,
           daemon->unescape_callback_cls = va_arg (ap,
           daemon->unescape_callback_cls = va_arg (ap,
                                                   void *);
                                                   void *);
           break;
           break;
+        case MHD_OPTION_GNUTLS_PSK_CRED_HANDLER:
+          daemon->cred_callback = va_arg (ap,
+                                          MHD_PskServerCredentialsCallback);
+	  daemon->cred_callback_cls = va_arg (ap,
+					      void *);
+          break;
         default:
         default:
 #ifdef HAVE_MESSAGES
 #ifdef HAVE_MESSAGES
           if ( ( (opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
           if ( ( (opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
@@ -6419,6 +6501,8 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
           gnutls_priority_deinit (daemon->priority_cache);
           gnutls_priority_deinit (daemon->priority_cache);
           if (daemon->x509_cred)
           if (daemon->x509_cred)
             gnutls_certificate_free_credentials (daemon->x509_cred);
             gnutls_certificate_free_credentials (daemon->x509_cred);
+          if (daemon->psk_cred)
+              gnutls_psk_free_server_credentials (daemon->psk_cred);
         }
         }
 #endif /* HTTPS_SUPPORT */
 #endif /* HTTPS_SUPPORT */
 
 

+ 15 - 0
src/microhttpd/internal.h

@@ -1611,12 +1611,27 @@ struct MHD_Daemon
    */
    */
   gnutls_dh_params_t dh_params;
   gnutls_dh_params_t dh_params;
 
 
+  /**
+   * Server PSK credentials
+   */
+  gnutls_psk_server_credentials_t psk_cred;
+
 #if GNUTLS_VERSION_MAJOR >= 3
 #if GNUTLS_VERSION_MAJOR >= 3
   /**
   /**
    * Function that can be used to obtain the certificate.  Needed
    * Function that can be used to obtain the certificate.  Needed
    * for SNI support.  See #MHD_OPTION_HTTPS_CERT_CALLBACK.
    * for SNI support.  See #MHD_OPTION_HTTPS_CERT_CALLBACK.
    */
    */
   gnutls_certificate_retrieve_function2 *cert_callback;
   gnutls_certificate_retrieve_function2 *cert_callback;
+
+  /**
+   * Function that can be used to obtain the shared key.
+   */
+  MHD_PskServerCredentialsCallback cred_callback;
+
+  /**
+   * Closure for @e cred_callback.
+   */
+  void *cred_callback_cls;
 #endif
 #endif
 
 
   /**
   /**