libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 2c47a23dec110fb77e1cda36d6bdb83fc4d5e252
parent 2ed04522e24b801251d7fd1768b7fccfd7b8deac
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat, 14 Jul 2018 11:44:01 +0200

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

Diffstat:
MAUTHORS | 1+
MChangeLog | 4++++
Mdoc/libmicrohttpd.texi | 10++++++++++
Msrc/include/microhttpd.h | 38+++++++++++++++++++++++++++++++++-----
Msrc/include/microhttpd2.h | 35+++++++++++++++++++++++++++++++++++
Msrc/microhttpd/daemon.c | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/microhttpd/internal.h | 15+++++++++++++++
7 files changed, 187 insertions(+), 10 deletions(-)

diff --git a/AUTHORS b/AUTHORS @@ -58,6 +58,7 @@ Louis Benoit <louisbenoit@videotron.ca> Flavio Coelin <flavio.ceolin@intel.com> Silvio Clecio <silvioprog@gmail.com> Robert D Kosisko <rkocisko@gmail.com> +Tal Moaz <tmoaz@cisco.com> Documentation contributions also came from: Marco Maggi <marco.maggi-ipsu@poste.it> diff --git a/ChangeLog b/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 Integrate patch for checking digest authentication based on a digest, allowing servers to store passwords only hashed. diff --git a/doc/libmicrohttpd.texi b/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 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 @cindex digest auth @cindex random diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -1167,6 +1167,25 @@ typedef void /** + * 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. * * Passed in the varargs portion of #MHD_start_daemon. @@ -1489,7 +1508,15 @@ enum MHD_OPTION * testing clients against MHD, and 0 in production. This option * 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_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 diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h @@ -2181,6 +2181,41 @@ MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon, /** + * 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 * HTTPS daemon for client authentification. * diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c @@ -565,7 +565,6 @@ MHD_init_daemon_certificate (struct MHD_Daemon *daemon) return -1; } - /** * 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)) return GNUTLS_E_MEMORY_ERROR; 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: #ifdef HAVE_MESSAGES MHD_DLOG (daemon, @@ -2137,6 +2141,67 @@ MHD_tls_push_func_(gnutls_transport_ptr_t trnsp, #endif /* MHD_TLSLIB_DONT_SUPPRESS_SIGPIPE */ #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 * 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_CRD_CERTIFICATE, 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; default: #ifdef HAVE_MESSAGES @@ -2392,12 +2463,15 @@ internal_add_connection (struct MHD_Daemon *daemon, return MHD_NO; } #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 */ - 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 */ #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 */ if (daemon->https_mem_trust) gnutls_certificate_server_set_request (connection->tls_session, @@ -2407,7 +2481,8 @@ internal_add_connection (struct MHD_Daemon *daemon, goto cleanup; #endif /* ! HTTPS_SUPPORT */ } - + gnutls_session_set_ptr (connection->tls_session, + connection); MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); /* Firm check under lock. */ @@ -5070,6 +5145,7 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_URI_LOG_CALLBACK: case MHD_OPTION_EXTERNAL_LOGGER: case MHD_OPTION_UNESCAPE_CALLBACK: + case MHD_OPTION_GNUTLS_PSK_CRED_HANDLER: if (MHD_YES != parse_options (daemon, servaddr, opt, @@ -5100,6 +5176,12 @@ parse_options_va (struct MHD_Daemon *daemon, daemon->unescape_callback_cls = va_arg (ap, void *); 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: #ifdef HAVE_MESSAGES if ( ( (opt >= MHD_OPTION_HTTPS_MEM_KEY) && @@ -6419,6 +6501,8 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) gnutls_priority_deinit (daemon->priority_cache); if (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 */ diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h @@ -1611,12 +1611,27 @@ struct MHD_Daemon */ gnutls_dh_params_t dh_params; + /** + * Server PSK credentials + */ + gnutls_psk_server_credentials_t psk_cred; + #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; + + /** + * Function that can be used to obtain the shared key. + */ + MHD_PskServerCredentialsCallback cred_callback; + + /** + * Closure for @e cred_callback. + */ + void *cred_callback_cls; #endif /**