commit fe4e71ecaa788e73582b7ee29d1835a3e3112be3
parent 65c3125ced95cc8f6d151f8c66e0d6a06255f04f
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 25 Dec 2010 20:58:06 +0000
client certs and basic auth support, unmodified patch from MS
Diffstat:
11 files changed, 489 insertions(+), 20 deletions(-)
diff --git a/AUTHORS b/AUTHORS
@@ -4,6 +4,7 @@ Nils Durner <durner@gnunet.org> (W32 port)
Sagie Amir (TLS/SSL support using GNUtls)
Richard Alimi <rich@velvetsea.net> (performance)
Amr Ali <amr.ali.cc@gmail.com> (digest authentication)
+Matthieu Speder <mspeder@users.sourceforge.net> (basic authentication, client certificates)
Code contributions also came from:
Chris GauthierDickey <chrisg@cs.du.edu>
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,6 @@
+Sat Dec 25 21:57:14 CET 2010
+ Adding support for basic authentication and client SSL certificates. -MS
+
Thu Dec 23 15:40:36 CET 2010
Increasing nonce length to 128 to support digest authentication
with Opera (see #1633).
diff --git a/configure.ac b/configure.ac
@@ -325,18 +325,18 @@ AC_MSG_RESULT($enable_https)
AM_CONDITIONAL(ENABLE_HTTPS, test "$enable_https" = "yes")
# optional: HTTP Digest Auth support. Enabled by default
-AC_MSG_CHECKING(whether to support HTTP Digest authentication)
+AC_MSG_CHECKING(whether to support HTTP basic and digest authentication)
AC_ARG_ENABLE([dauth],
AS_HELP_STRING([--disable-dauth],
- [disable HTTP Digest Auth support]),
+ [disable HTTP basic and digest Auth support]),
[enable_dauth=${enableval}],
[enable_dauth=no])
if test "$enable_dauth" = "yes"
then
- AC_DEFINE([DAUTH_SUPPORT],[1],[include Digest Auth support])
+ AC_DEFINE([DAUTH_SUPPORT],[1],[include basic and digest Auth support])
else
- AC_DEFINE([DAUTH_SUPPORT],[0],[disable Digest Auth support])
+ AC_DEFINE([DAUTH_SUPPORT],[0],[disable basic and digest Auth support])
fi
AC_MSG_RESULT($enable_dauth)
@@ -416,7 +416,7 @@ AC_MSG_NOTICE([Configuration Summary:
libcurl (testing): ${MSG_CURL}
Target directory: ${prefix}
Messages: ${enable_messages}
- HTTP Digest Auth: ${enable_dauth}
+ HTTP Authentic.: ${enable_dauth}
Postproc: ${enable_postprocessor}
HTTPS support: ${enable_https}
])
diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi
@@ -117,7 +117,7 @@ GNU libmicrohttpd is a GNU package.
* microhttpd-inspect:: Implementing external @code{select}.
* microhttpd-requests:: Handling requests.
* microhttpd-responses:: Building responses to requests.
-* microhttpd-dauth:: Utilizing Digest Authentication.
+* microhttpd-dauth:: Utilizing Authentication.
* microhttpd-post:: Adding a @code{POST} processor.
* microhttpd-info:: Obtaining status information.
@@ -259,7 +259,6 @@ alternative type and also define @code{MHD_LONG_LONG_PRINTF} to the
corresponding format string for printing such a data type (without
the percent sign).
-
@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@c ------------------------------------------------------------
@@ -449,6 +448,20 @@ HTTPS daemon. This option should be followed by an
"const char*" argument.
This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_KEY'.
+@item MHD_OPTION_HTTPS_MEM_TRUST
+@cindex SSL
+@cindex TLS
+Memory pointer to the CA certificate to be used by the
+HTTPS daemon to authenticate and trust clients certificates.
+This option should be followed by an "const char*" argument.
+The presence of this option activates the request of certificate
+to the client. The request to the client is marked optional, and
+it is the responsability of the server to check the presence
+of the certificate if needed.
+Note that most browsers will only present a client certificate
+only if they have one matching the specified CA, not sending
+any certificate otherwise.
+
@item MHD_OPTION_HTTPS_CRED_TYPE
@cindex SSL
@cindex TLS
@@ -680,6 +693,12 @@ Takes no extra arguments. Allows finding out the TLS/SSL protocol used
Takes no extra arguments. Allows access to the underlying GNUtls session
(HTTPS connections only).
+@item MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT
+Allows access to the underlying GNUtls client certificate.
+Equivalent to calling directly MHD_cert_auth_get_certificate.
+Takes no extra arguments.
+(HTTPS connections only).
+
@end table
@end deftp
@@ -1263,7 +1282,7 @@ the @code{MHD_Response} object is released.
@c ------------------------------------------------------------
@node microhttpd-response create
-@section Creating response objects
+@section Creating a response object
@deftypefun {struct MHD_Response *} MHD_create_response_from_callback (uint64_t size, size_t block_size, MHD_ContentReaderCallback crc, void *crc_cls, MHD_ContentReaderFreeCallback crfc)
@@ -1457,7 +1476,68 @@ We should not modify the value, unless we know what we are doing.
@c ------------------------------------------------------------
@node microhttpd-dauth
-@chapter Utilizing Digest Authentication
+@chapter Utilizing Authentication
+
+@noindent
+@mhd{} support three types of client authentication.
+
+Basic authentication uses a simple authentication method based
+on BASE64 algorithm. Username and password are exchanged in clear
+between the client and the server, so this method must only be used
+for non-sensitive content or when the session is protected with https.
+When using basic authentication @mhd{} will have access to the clear
+password, possibily allowing to create a chained authentication
+toward an external authentication server.
+
+Digest authentication uses a one-way authentication method based
+on MD5 hash algorithm. Only the hash will transit over the network,
+hence protecting the user password. The nonce will prevent replay
+attacks. This method is appropriate for general use, especially
+when https is not used to encrypt the session.
+
+Client certificate authentication uses a X.509 certificate from
+the client. This is the strongest authentication mechanism but it
+requires the use of https. Client certificate authentication can
+be used simultaneously with Basic or Digest Authentication in order
+to provide a two levels authentication (like for instance separate
+machine and user authentication).
+
+@menu
+* microhttpd-dauth basic:: Using Basic Authentication.
+* microhttpd-dauth digest:: Using Digest Authentication.
+* microhttpd-dauth cert:: Using Client Certificate Authentication.
+@end menu
+
+@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+@c ------------------------------------------------------------
+@node microhttpd-dauth basic
+@section Using Basic Authentication
+
+@deftypefun {char *} MHD_basic_auth_get_username_password (struct MHD_Connection *connection, char** password)
+Get the username and password from the basic authorization header sent by the client.
+Return @mynull{} if no username could be found, a pointer to the username if found.
+If returned value is not @mynull{}, the value must be free()'ed.
+
+@var{password} reference a buffer to store the password. It can be @mynull{}.
+If returned value is not @mynull{}, the value must be free()'ed.
+@end deftypefun
+
+@deftypefun {int} MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection, const char *realm, struct MHD_Response *response)
+Queues a response to request basic authentication from the client.
+Return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
+
+@var{realm} must reference to a zero-terminated string representing the realm.
+
+@var{response} a response structure to specify what shall be presented to the
+client with a 401 HTTP status.
+@end deftypefun
+
+@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+@c ------------------------------------------------------------
+@node microhttpd-dauth digest
+@section Using Digest Authentication
@deftypefun {char *} MHD_digest_auth_get_username (struct MHD_Connection *connection)
Find and return a pointer to the username value from the request header.
@@ -1467,7 +1547,7 @@ If returned value is not @mynull{}, the value must be free()'ed.
@deftypefun int MHD_digest_auth_check (struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout)
Checks if the provided values in the WWW-Authenticate header are valid
-and sound according to RFC2716. If valid return MHD_YES, otherwise return MHD_NO.
+and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}.
@var{realm} must reference to a zero-terminated string representing the realm.
@@ -1483,7 +1563,9 @@ Most of the time it is sound to specify 300 seconds as its values.
@deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale)
Queues a response to request authentication from the client,
-return MHD_YES if successful, otherwise MHD_NO.
+return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
+
+@var{realm} must reference to a zero-terminated string representing the realm.
@var{opaque} must reference to a zero-terminated string representing a value
that gets passed to the client and expected to be passed again to the server
@@ -1494,8 +1576,8 @@ client with a 401 HTTP status.
@var{signal_stale} a value that signals "stale=true" in the response header to
indicate the invalidity of the nonce and no need to ask for authentication
-parameters and only a new nonce gets generated. MHD_YES to generate a new
-nonce, MHD_NO to ask for authentication parameters.
+parameters and only a new nonce gets generated. @code{MHD_YES} to generate a new
+nonce, @code{MHD_NO} to ask for authentication parameters.
@end deftypefun
Example: handling digest authentication requests and responses.
@@ -1563,6 +1645,39 @@ ahc_echo (void *cls,
@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@c ------------------------------------------------------------
+@node microhttpd-dauth cert
+@section Using Client Certificate Authentication
+
+@deftypefun {void *} MHD_cert_auth_get_certificate (struct MHD_Connection *connection)
+Get the client's X.509 certificate.
+Return @mynull{} if no valid client certificate was found, a pointer to the certificate
+(which can be casted to gnutls_x509_crt_t) if found.
+The certificate is cached between calls for a same https session and must not but
+manually modified or free()'ed.
+@end deftypefun
+
+@deftypefun {char *} MHD_cert_auth_get_dn (struct MHD_Connection *connection)
+Get the distinguished name from the client's certificate.
+Return @mynull{} if the certificate doesn't contain a dn or if no valid certificate was
+found, a pointer to the dn if found. If returned value is not @mynull{}, the value must
+be free()'ed.
+@end deftypefun
+
+@deftypefun {char *} MHD_cert_auth_get_alt_name (struct MHD_Connection *connection, int nametype, unsigned int index)
+Get the alternative name of specified type from the client's certificate.
+Return @mynull{} if the certificate doesn't contain a matching alternative name or if no
+valid certificate was found, a pointer to the alternative name if found. If returned
+value is not @mynull{}, the value must be free()'ed.
+
+@var{nametype} The requested name type (of type 'enum gnutls_x509_subject_alt_name_t')
+
+@var{index} The position of the alternative name if multiple names are matching the
+requested type, 0 for the first matching name
+@end deftypefun
+
+@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+@c ------------------------------------------------------------
@node microhttpd-post
@chapter Adding a @code{POST} processor
@cindex POST method
diff --git a/src/daemon/EXPORT.sym b/src/daemon/EXPORT.sym
@@ -27,3 +27,8 @@ MHD_get_version
MHD_digest_auth_get_username
MHD_digest_auth_check
MHD_queue_auth_fail_response
+MHD_basic_auth_get_username_password
+MHD_queue_basic_auth_fail_response
+MHD_cert_auth_get_certificate
+MHD_cert_auth_get_dn
+MHD_cert_auth_get_alt_name
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
@@ -37,7 +37,8 @@ endif
if ENABLE_DAUTH
libmicrohttpd_la_SOURCES += \
digestauth.c \
- md5.c md5.h
+ md5.c md5.h \
+ base64.c base64.h
endif
if ENABLE_HTTPS
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
@@ -2316,6 +2316,10 @@ MHD_get_connection_info (struct MHD_Connection *connection,
if (connection->tls_session == NULL)
return NULL;
return (const union MHD_ConnectionInfo *) &connection->tls_session;
+#if DAUTH_SUPPORT
+ case MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT:
+ return (const union MHD_ConnectionInfo *) MHD_cert_auth_get_certificate(connection);
+#endif
#endif
case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
return (const union MHD_ConnectionInfo *) &connection->addr;
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
@@ -439,6 +439,19 @@ MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
gnutls_datum_t key;
gnutls_datum_t cert;
+ if (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;
+ }
+ }
+
/* certificate & key loaded from memory */
if (daemon->https_mem_cert && daemon->https_mem_key)
{
@@ -987,6 +1000,10 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
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);
+ }
}
#endif
@@ -1058,6 +1075,8 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
#if HTTPS_SUPPORT
if (pos->tls_session != NULL)
gnutls_deinit (pos->tls_session);
+ if (pos->client_cert != NULL)
+ gnutls_x509_crt_deinit (pos->client_cert);
#endif
MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
if (pos->response != NULL)
@@ -1474,6 +1493,16 @@ parse_options_va (struct MHD_Daemon *daemon,
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
+ else
+ FPRINTF (stderr,
+ "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 = va_arg (ap, gnutls_credentials_type_t);
break;
@@ -1561,6 +1590,7 @@ parse_options_va (struct MHD_Daemon *daemon,
case MHD_OPTION_SOCK_ADDR:
case MHD_OPTION_HTTPS_MEM_KEY:
case MHD_OPTION_HTTPS_MEM_CERT:
+ case MHD_OPTION_HTTPS_MEM_TRUST:
case MHD_OPTION_HTTPS_PRIORITIES:
case MHD_OPTION_ARRAY:
if (MHD_YES != parse_options (daemon,
@@ -1606,8 +1636,8 @@ parse_options_va (struct MHD_Daemon *daemon,
break;
default:
#if HAVE_MESSAGES
- if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
- (opt <= MHD_OPTION_HTTPS_PRIORITIES))
+ if (((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
+ (opt <= MHD_OPTION_HTTPS_PRIORITIES)) || (opt == MHD_OPTION_HTTPS_MEM_TRUST))
{
FPRINTF (stderr,
"MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
diff --git a/src/daemon/digestauth.c b/src/daemon/digestauth.c
@@ -19,13 +19,15 @@
/**
* @file digestauth.c
- * @brief Implements HTTP/1.1 Digest Auth according to RFC2617
+ * @brief Implements various HTTP authentication methods
* @author Amr Ali
+ * @author Matthieu Speder
*/
#include "platform.h"
#include "internal.h"
#include "md5.h"
+#include "base64.h"
#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
@@ -35,6 +37,11 @@
#define _BASE "Digest "
/**
+ * Beginning string for any valid Basic authentication header.
+ */
+#define _BASIC_BASE "Basic "
+
+/**
* Maximum length of a username for digest authentication.
*/
#define MAX_USERNAME_LENGTH 128
@@ -636,5 +643,218 @@ MHD_queue_auth_fail_response(struct MHD_Connection *connection,
return ret;
}
+/**
+ * Get the username and password from the basic authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @param password a pointer for the password
+ * @return NULL if no username could be found, a pointer
+ * to the username if found
+ */
+char *
+MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
+ char** password) {
+ size_t len;
+ const char *header;
+ char *decode;
+ const char *separator;
+ char *user;
+
+ header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_AUTHORIZATION);
+ if (header == NULL)
+ return NULL;
+ if (strncmp(header, _BASIC_BASE, strlen(_BASIC_BASE)) != 0)
+ return NULL;
+ header += strlen(_BASIC_BASE);
+ decode = BASE64Decode(header);
+ if (decode == NULL) {
+#if HAVE_MESSAGES
+ MHD_DLOG(connection->daemon, "Error decoding basic authentication\n");
+#endif
+ return NULL;
+ }
+ /* Find user:password pattern */
+ separator = strstr(decode, ":");
+ if (separator == NULL) {
+#if HAVE_MESSAGES
+ MHD_DLOG(connection->daemon,
+ "Basic authentication doesn't contain ':' separator\n");
+#endif
+ free(decode);
+ return NULL;
+ }
+ user = strndup(decode, separator - decode);
+ if (password != NULL) {
+ *password = strdup(separator + 1);
+ }
+ free(decode);
+ return user;
+}
+
+/**
+ * Queues a response to request basic authentication from the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm the realm presented to the client
+ * @return MHD_YES on success, MHD_NO otherwise
+ */
+int MHD_queue_basic_auth_fail_response(struct MHD_Connection *connection,
+ const char *realm, struct MHD_Response *response) {
+ int ret;
+ size_t hlen = strlen(realm) + sizeof("Basic realm=\"\"");
+ char header[hlen];
+ snprintf(header, sizeof(header), "Basic realm=\"%s\"", realm);
+ ret = MHD_add_response_header(response, MHD_HTTP_HEADER_WWW_AUTHENTICATE,
+ header);
+ if (MHD_YES == ret)
+ ret = MHD_queue_response(connection, MHD_HTTP_UNAUTHORIZED, response);
+ return ret;
+}
+
+#if HTTPS_SUPPORT
+
+/**
+ * Get the client's certificate
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no valid client certificate could be found, a pointer
+ * to the certificate if found
+ */
+void*
+MHD_cert_auth_get_certificate(struct MHD_Connection *connection) {
+
+ if (connection->client_cert == NULL && connection->client_cert_status == 0) {
+ if (connection->tls_session == NULL) {
+ connection->client_cert_status = GNUTLS_CERT_INVALID;
+ return NULL;
+ }
+
+ if (gnutls_certificate_verify_peers2(connection->tls_session,
+ &connection->client_cert_status)) {
+ connection->client_cert_status = GNUTLS_CERT_INVALID;
+ return NULL;
+ }
+
+ unsigned int listsize;
+ const gnutls_datum_t * pcert = gnutls_certificate_get_peers(
+ connection->tls_session, &listsize);
+ if (pcert == NULL || listsize == 0) {
+#if HAVE_MESSAGES
+ MHD_DLOG(connection->daemon,
+ "Failed to retrieve client certificate chain\n");
+#endif
+ connection->client_cert_status = GNUTLS_CERT_INVALID;
+ return NULL;
+ }
+
+ if (gnutls_x509_crt_init(&connection->client_cert)) {
+#if HAVE_MESSAGES
+ MHD_DLOG(connection->daemon,
+ "Failed to initialize client certificate\n");
+#endif
+ connection->client_cert = NULL;
+ connection->client_cert_status = GNUTLS_CERT_INVALID;
+ return NULL;
+ }
+ if (gnutls_x509_crt_import(connection->client_cert, &pcert[0],
+ GNUTLS_X509_FMT_DER)) {
+#if HAVE_MESSAGES
+ MHD_DLOG(connection->daemon,
+ "Failed to import client certificate\n");
+#endif
+ gnutls_x509_crt_deinit(connection->client_cert);
+ connection->client_cert = NULL;
+ connection->client_cert_status = GNUTLS_CERT_INVALID;
+ return NULL;
+ }
+ }
+
+ return connection->client_cert;
+}
+
+/**
+ * Get the distinguished name from the client's certificate
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no dn or certificate could be found, a pointer
+ * to the dn if found
+ */
+char *
+MHD_cert_auth_get_dn(struct MHD_Connection *connection) {
+
+ char* buf;
+ size_t lbuf = 0;
+
+ gnutls_x509_crt_t cert = MHD_cert_auth_get_certificate(connection);
+ if (cert == NULL)
+ return NULL;
+
+ gnutls_x509_crt_get_dn(cert, NULL, &lbuf);
+ buf = malloc(lbuf);
+ if (buf == NULL) {
+#if HAVE_MESSAGES
+ MHD_DLOG(connection->daemon,
+ "Failed to allocate memory for certificate dn\n");
+#endif
+ return NULL;
+ }
+ gnutls_x509_crt_get_dn(cert, buf, &lbuf);
+ return buf;
+
+}
+
+/**
+ * Get the alternative name of specified type from the client's certificate
+ *
+ * @param connection The MHD connection structure
+ * @param nametype The requested name type
+ * @param index The position of the alternative name if multiple names are
+ * matching the requested type, 0 for the first matching name
+ * @return NULL if no matching alternative name could be found, a pointer
+ * to the alternative name if found
+ */
+char *
+MHD_cert_auth_get_alt_name(struct MHD_Connection *connection, int nametype, unsigned int index) {
+
+ char* buf;
+ size_t lbuf;
+ unsigned int seq = 0;
+ unsigned int subseq = 0;
+ int result;
+ unsigned int type;
+
+ gnutls_x509_crt_t cert = MHD_cert_auth_get_certificate(connection);
+ if (cert == NULL)
+ return NULL;
+
+ for (;; seq++) {
+ lbuf = 0;
+ result = gnutls_x509_crt_get_subject_alt_name2(cert, seq, NULL, &lbuf,
+ &type, NULL);
+ if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ return NULL;
+ if (type != nametype)
+ continue;
+ if (subseq != index) {
+ subseq++;
+ continue;
+ }
+ buf = malloc(lbuf);
+ if (buf == NULL) {
+#if HAVE_MESSAGES
+ MHD_DLOG(connection->daemon,
+ "Failed to allocate memory for certificate alt name\n");
+#endif
+ return NULL;
+ }
+ gnutls_x509_crt_get_subject_alt_name2(cert, seq, buf, &lbuf, NULL, NULL);
+ return buf;
+
+ }
+
+}
+
+#endif /* HTTPS */
/* end of digestauth.c */
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
@@ -705,6 +705,17 @@ struct MHD_Connection
* Memory location to return for protocol session info.
*/
int cipher;
+
+ /**
+ * Validation status of client's certificate.
+ */
+ gnutls_certificate_status_t client_cert_status;
+
+ /**
+ * Client's certificate.
+ */
+ gnutls_x509_crt_t client_cert;
+
#endif
};
@@ -920,6 +931,11 @@ struct MHD_Daemon
*/
const char *https_mem_cert;
+ /**
+ * Pointer to our SSL/TLS certificate authority (in ASCII) in memory.
+ */
+ const char *https_mem_trust;
+
#endif
#ifdef DAUTH_SUPPORT
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
@@ -580,9 +580,14 @@ enum MHD_OPTION
* Desired size of the stack for threads created by MHD. Followed
* by an argument of type 'size_t'. Use 0 for system 'default'.
*/
- MHD_OPTION_THREAD_STACK_SIZE = 19
-
+ MHD_OPTION_THREAD_STACK_SIZE = 19,
+ /**
+ * Memory pointer for the certificate (ca.pem) to be used by the
+ * HTTPS daemon for client authentification.
+ * This option should be followed by a "const char*" argument.
+ */
+ MHD_OPTION_HTTPS_MEM_TRUST =20
};
@@ -719,7 +724,12 @@ enum MHD_ConnectionInfoType
/**
* Get the GNUTLS session handle.
*/
- MHD_CONNECTION_INFO_GNUTLS_SESSION
+ MHD_CONNECTION_INFO_GNUTLS_SESSION,
+
+ /**
+ * Get the GNUTLS client certificate handle.
+ */
+ MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT
};
/**
@@ -1430,6 +1440,65 @@ MHD_queue_auth_fail_response (struct MHD_Connection *connection,
int signal_stale);
+/**
+ * Get the username and password from the basic authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @param password a pointer for the password
+ * @return NULL if no username could be found, a pointer
+ * to the username if found
+ */
+char *
+MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
+ char** password);
+
+/**
+ * Queues a response to request basic authentication from the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm the realm presented to the client
+ * @return MHD_YES on success, MHD_NO otherwise
+ */
+int
+MHD_queue_basic_auth_fail_response(struct MHD_Connection *connection,
+ const char *realm,
+ struct MHD_Response *response);
+
+/**
+ * Get the client's certificate
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no valid client certificate could be found, a pointer
+ * to the certificate if found
+ */
+void*
+MHD_cert_auth_get_certificate(struct MHD_Connection *connection);
+
+/**
+ * Get the distinguished name from the client's certificate
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no dn or certificate could be found, a pointer
+ * to the dn if found
+ */
+char *
+MHD_cert_auth_get_dn(struct MHD_Connection *connection);
+
+/**
+ * Get the alternative name of specified type from the client's certificate
+ *
+ * @param connection The MHD connection structure
+ * @param nametype The requested name type
+ * @param index The position of the alternative name if multiple names are
+ * matching the requested type, 0 for the first matching name
+ * @return NULL if no matching alternative name could be found, a pointer
+ * to the alternative name if found
+ */
+char *
+MHD_cert_auth_get_alt_name(struct MHD_Connection *connection,
+ int nametype,
+ unsigned int index);
+
/* ********************** generic query functions ********************** */
/**
@@ -1454,6 +1523,11 @@ union MHD_ConnectionInfo
void * /* gnutls_session_t */ tls_session;
/**
+ * GNUtls client certificate handle, of type "gnutls_x509_crt_t".
+ */
+ void * /* gnutls_x509_crt_t */ client_cert;
+
+ /**
* Address information for the client.
*/
struct sockaddr_in * client_addr;