Parcourir la source

client certs and basic auth support, unmodified patch from MS

Christian Grothoff il y a 15 ans
Parent
commit
fe4e71ecaa

+ 1 - 0
AUTHORS

@@ -4,6 +4,7 @@ Nils Durner <[email protected]> (W32 port)
 Sagie Amir (TLS/SSL support using GNUtls)
 Richard Alimi <[email protected]> (performance)
 Amr Ali <[email protected]> (digest authentication)
+Matthieu Speder <[email protected]> (basic authentication, client certificates)
 
 Code contributions also came from:
 Chris GauthierDickey <[email protected]>

+ 3 - 0
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).

+ 5 - 5
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}
 ])

+ 123 - 8
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.
@@ -1562,6 +1644,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

+ 5 - 0
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

+ 2 - 1
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

+ 4 - 0
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;

+ 32 - 2
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)
@@ -1472,6 +1491,16 @@ parse_options_va (struct MHD_Daemon *daemon,
 	    FPRINTF (stderr,
 		     "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
 		     opt);	  
+#endif
+          break;
+        case MHD_OPTION_HTTPS_MEM_TRUST:
+	  if (0 != (daemon->options & MHD_USE_SSL))
+	    daemon->https_mem_trust = va_arg (ap, const char *);
+#if HAVE_MESSAGES
+	  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:
@@ -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",

+ 221 - 1
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)
 
@@ -34,6 +36,11 @@
  */
 #define _BASE		"Digest "
 
+/**
+ * Beginning string for any valid Basic authentication header.
+ */
+#define _BASIC_BASE		"Basic "
+
 /**
  * Maximum length of a username for digest authentication.
  */
@@ -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 */

+ 16 - 0
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

+ 77 - 3
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 ********************** */
 
 /**
@@ -1453,6 +1522,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.
    */