aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--ChangeLog3
-rw-r--r--configure.ac10
-rw-r--r--doc/microhttpd.texi131
-rw-r--r--src/daemon/EXPORT.sym5
-rw-r--r--src/daemon/Makefile.am3
-rw-r--r--src/daemon/connection.c4
-rw-r--r--src/daemon/daemon.c34
-rw-r--r--src/daemon/digestauth.c222
-rw-r--r--src/daemon/internal.h16
-rw-r--r--src/include/microhttpd.h80
11 files changed, 489 insertions, 20 deletions
diff --git a/AUTHORS b/AUTHORS
index 9f2bcac1..68628285 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -4,6 +4,7 @@ Nils Durner <durner@gnunet.org> (W32 port)
4Sagie Amir (TLS/SSL support using GNUtls) 4Sagie Amir (TLS/SSL support using GNUtls)
5Richard Alimi <rich@velvetsea.net> (performance) 5Richard Alimi <rich@velvetsea.net> (performance)
6Amr Ali <amr.ali.cc@gmail.com> (digest authentication) 6Amr Ali <amr.ali.cc@gmail.com> (digest authentication)
7Matthieu Speder <mspeder@users.sourceforge.net> (basic authentication, client certificates)
7 8
8Code contributions also came from: 9Code contributions also came from:
9Chris GauthierDickey <chrisg@cs.du.edu> 10Chris GauthierDickey <chrisg@cs.du.edu>
diff --git a/ChangeLog b/ChangeLog
index 4754f80a..07345772 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
1Sat Dec 25 21:57:14 CET 2010
2 Adding support for basic authentication and client SSL certificates. -MS
3
1Thu Dec 23 15:40:36 CET 2010 4Thu Dec 23 15:40:36 CET 2010
2 Increasing nonce length to 128 to support digest authentication 5 Increasing nonce length to 128 to support digest authentication
3 with Opera (see #1633). 6 with Opera (see #1633).
diff --git a/configure.ac b/configure.ac
index 2d464b12..b2a53fed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -325,18 +325,18 @@ AC_MSG_RESULT($enable_https)
325AM_CONDITIONAL(ENABLE_HTTPS, test "$enable_https" = "yes") 325AM_CONDITIONAL(ENABLE_HTTPS, test "$enable_https" = "yes")
326 326
327# optional: HTTP Digest Auth support. Enabled by default 327# optional: HTTP Digest Auth support. Enabled by default
328AC_MSG_CHECKING(whether to support HTTP Digest authentication) 328AC_MSG_CHECKING(whether to support HTTP basic and digest authentication)
329AC_ARG_ENABLE([dauth], 329AC_ARG_ENABLE([dauth],
330 AS_HELP_STRING([--disable-dauth], 330 AS_HELP_STRING([--disable-dauth],
331 [disable HTTP Digest Auth support]), 331 [disable HTTP basic and digest Auth support]),
332 [enable_dauth=${enableval}], 332 [enable_dauth=${enableval}],
333 [enable_dauth=no]) 333 [enable_dauth=no])
334 334
335if test "$enable_dauth" = "yes" 335if test "$enable_dauth" = "yes"
336then 336then
337 AC_DEFINE([DAUTH_SUPPORT],[1],[include Digest Auth support]) 337 AC_DEFINE([DAUTH_SUPPORT],[1],[include basic and digest Auth support])
338else 338else
339 AC_DEFINE([DAUTH_SUPPORT],[0],[disable Digest Auth support]) 339 AC_DEFINE([DAUTH_SUPPORT],[0],[disable basic and digest Auth support])
340fi 340fi
341AC_MSG_RESULT($enable_dauth) 341AC_MSG_RESULT($enable_dauth)
342 342
@@ -416,7 +416,7 @@ AC_MSG_NOTICE([Configuration Summary:
416 libcurl (testing): ${MSG_CURL} 416 libcurl (testing): ${MSG_CURL}
417 Target directory: ${prefix} 417 Target directory: ${prefix}
418 Messages: ${enable_messages} 418 Messages: ${enable_messages}
419 HTTP Digest Auth: ${enable_dauth} 419 HTTP Authentic.: ${enable_dauth}
420 Postproc: ${enable_postprocessor} 420 Postproc: ${enable_postprocessor}
421 HTTPS support: ${enable_https} 421 HTTPS support: ${enable_https}
422]) 422])
diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi
index 507490d0..aaeb5da9 100644
--- a/doc/microhttpd.texi
+++ b/doc/microhttpd.texi
@@ -117,7 +117,7 @@ GNU libmicrohttpd is a GNU package.
117* microhttpd-inspect:: Implementing external @code{select}. 117* microhttpd-inspect:: Implementing external @code{select}.
118* microhttpd-requests:: Handling requests. 118* microhttpd-requests:: Handling requests.
119* microhttpd-responses:: Building responses to requests. 119* microhttpd-responses:: Building responses to requests.
120* microhttpd-dauth:: Utilizing Digest Authentication. 120* microhttpd-dauth:: Utilizing Authentication.
121* microhttpd-post:: Adding a @code{POST} processor. 121* microhttpd-post:: Adding a @code{POST} processor.
122* microhttpd-info:: Obtaining status information. 122* microhttpd-info:: Obtaining status information.
123 123
@@ -259,7 +259,6 @@ alternative type and also define @code{MHD_LONG_LONG_PRINTF} to the
259corresponding format string for printing such a data type (without 259corresponding format string for printing such a data type (without
260the percent sign). 260the percent sign).
261 261
262
263@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 262@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
264 263
265@c ------------------------------------------------------------ 264@c ------------------------------------------------------------
@@ -449,6 +448,20 @@ HTTPS daemon. This option should be followed by an
449"const char*" argument. 448"const char*" argument.
450This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_KEY'. 449This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_KEY'.
451 450
451@item MHD_OPTION_HTTPS_MEM_TRUST
452@cindex SSL
453@cindex TLS
454Memory pointer to the CA certificate to be used by the
455HTTPS daemon to authenticate and trust clients certificates.
456This option should be followed by an "const char*" argument.
457The presence of this option activates the request of certificate
458to the client. The request to the client is marked optional, and
459it is the responsability of the server to check the presence
460of the certificate if needed.
461Note that most browsers will only present a client certificate
462only if they have one matching the specified CA, not sending
463any certificate otherwise.
464
452@item MHD_OPTION_HTTPS_CRED_TYPE 465@item MHD_OPTION_HTTPS_CRED_TYPE
453@cindex SSL 466@cindex SSL
454@cindex TLS 467@cindex TLS
@@ -680,6 +693,12 @@ Takes no extra arguments. Allows finding out the TLS/SSL protocol used
680Takes no extra arguments. Allows access to the underlying GNUtls session 693Takes no extra arguments. Allows access to the underlying GNUtls session
681(HTTPS connections only). 694(HTTPS connections only).
682 695
696@item MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT
697Allows access to the underlying GNUtls client certificate.
698Equivalent to calling directly MHD_cert_auth_get_certificate.
699Takes no extra arguments.
700(HTTPS connections only).
701
683@end table 702@end table
684@end deftp 703@end deftp
685 704
@@ -1263,7 +1282,7 @@ the @code{MHD_Response} object is released.
1263 1282
1264@c ------------------------------------------------------------ 1283@c ------------------------------------------------------------
1265@node microhttpd-response create 1284@node microhttpd-response create
1266@section Creating response objects 1285@section Creating a response object
1267 1286
1268 1287
1269@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) 1288@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.
1457 1476
1458@c ------------------------------------------------------------ 1477@c ------------------------------------------------------------
1459@node microhttpd-dauth 1478@node microhttpd-dauth
1460@chapter Utilizing Digest Authentication 1479@chapter Utilizing Authentication
1480
1481@noindent
1482@mhd{} support three types of client authentication.
1483
1484Basic authentication uses a simple authentication method based
1485on BASE64 algorithm. Username and password are exchanged in clear
1486between the client and the server, so this method must only be used
1487for non-sensitive content or when the session is protected with https.
1488When using basic authentication @mhd{} will have access to the clear
1489password, possibily allowing to create a chained authentication
1490toward an external authentication server.
1491
1492Digest authentication uses a one-way authentication method based
1493on MD5 hash algorithm. Only the hash will transit over the network,
1494hence protecting the user password. The nonce will prevent replay
1495attacks. This method is appropriate for general use, especially
1496when https is not used to encrypt the session.
1497
1498Client certificate authentication uses a X.509 certificate from
1499the client. This is the strongest authentication mechanism but it
1500requires the use of https. Client certificate authentication can
1501be used simultaneously with Basic or Digest Authentication in order
1502to provide a two levels authentication (like for instance separate
1503machine and user authentication).
1504
1505@menu
1506* microhttpd-dauth basic:: Using Basic Authentication.
1507* microhttpd-dauth digest:: Using Digest Authentication.
1508* microhttpd-dauth cert:: Using Client Certificate Authentication.
1509@end menu
1510
1511@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1512
1513@c ------------------------------------------------------------
1514@node microhttpd-dauth basic
1515@section Using Basic Authentication
1516
1517@deftypefun {char *} MHD_basic_auth_get_username_password (struct MHD_Connection *connection, char** password)
1518Get the username and password from the basic authorization header sent by the client.
1519Return @mynull{} if no username could be found, a pointer to the username if found.
1520If returned value is not @mynull{}, the value must be free()'ed.
1521
1522@var{password} reference a buffer to store the password. It can be @mynull{}.
1523If returned value is not @mynull{}, the value must be free()'ed.
1524@end deftypefun
1525
1526@deftypefun {int} MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection, const char *realm, struct MHD_Response *response)
1527Queues a response to request basic authentication from the client.
1528Return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
1529
1530@var{realm} must reference to a zero-terminated string representing the realm.
1531
1532@var{response} a response structure to specify what shall be presented to the
1533client with a 401 HTTP status.
1534@end deftypefun
1535
1536@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1537
1538@c ------------------------------------------------------------
1539@node microhttpd-dauth digest
1540@section Using Digest Authentication
1461 1541
1462@deftypefun {char *} MHD_digest_auth_get_username (struct MHD_Connection *connection) 1542@deftypefun {char *} MHD_digest_auth_get_username (struct MHD_Connection *connection)
1463Find and return a pointer to the username value from the request header. 1543Find 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.
1467 1547
1468@deftypefun int MHD_digest_auth_check (struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout) 1548@deftypefun int MHD_digest_auth_check (struct MHD_Connection *connection, const char *realm, const char *username, const char *password, unsigned int nonce_timeout)
1469Checks if the provided values in the WWW-Authenticate header are valid 1549Checks if the provided values in the WWW-Authenticate header are valid
1470and sound according to RFC2716. If valid return MHD_YES, otherwise return MHD_NO. 1550and sound according to RFC2716. If valid return @code{MHD_YES}, otherwise return @code{MHD_NO}.
1471 1551
1472@var{realm} must reference to a zero-terminated string representing the realm. 1552@var{realm} must reference to a zero-terminated string representing the realm.
1473 1553
@@ -1483,7 +1563,9 @@ Most of the time it is sound to specify 300 seconds as its values.
1483 1563
1484@deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale) 1564@deftypefun int MHD_queue_auth_fail_response (struct MHD_Connection *connection, const char *realm, const char *opaque, struct MHD_Response *response, int signal_stale)
1485Queues a response to request authentication from the client, 1565Queues a response to request authentication from the client,
1486return MHD_YES if successful, otherwise MHD_NO. 1566return @code{MHD_YES} if successful, otherwise @code{MHD_NO}.
1567
1568@var{realm} must reference to a zero-terminated string representing the realm.
1487 1569
1488@var{opaque} must reference to a zero-terminated string representing a value 1570@var{opaque} must reference to a zero-terminated string representing a value
1489that gets passed to the client and expected to be passed again to the server 1571that gets passed to the client and expected to be passed again to the server
@@ -1494,8 +1576,8 @@ client with a 401 HTTP status.
1494 1576
1495@var{signal_stale} a value that signals "stale=true" in the response header to 1577@var{signal_stale} a value that signals "stale=true" in the response header to
1496indicate the invalidity of the nonce and no need to ask for authentication 1578indicate the invalidity of the nonce and no need to ask for authentication
1497parameters and only a new nonce gets generated. MHD_YES to generate a new 1579parameters and only a new nonce gets generated. @code{MHD_YES} to generate a new
1498nonce, MHD_NO to ask for authentication parameters. 1580nonce, @code{MHD_NO} to ask for authentication parameters.
1499@end deftypefun 1581@end deftypefun
1500 1582
1501Example: handling digest authentication requests and responses. 1583Example: handling digest authentication requests and responses.
@@ -1563,6 +1645,39 @@ ahc_echo (void *cls,
1563@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1645@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1564 1646
1565@c ------------------------------------------------------------ 1647@c ------------------------------------------------------------
1648@node microhttpd-dauth cert
1649@section Using Client Certificate Authentication
1650
1651@deftypefun {void *} MHD_cert_auth_get_certificate (struct MHD_Connection *connection)
1652Get the client's X.509 certificate.
1653Return @mynull{} if no valid client certificate was found, a pointer to the certificate
1654(which can be casted to gnutls_x509_crt_t) if found.
1655The certificate is cached between calls for a same https session and must not but
1656manually modified or free()'ed.
1657@end deftypefun
1658
1659@deftypefun {char *} MHD_cert_auth_get_dn (struct MHD_Connection *connection)
1660Get the distinguished name from the client's certificate.
1661Return @mynull{} if the certificate doesn't contain a dn or if no valid certificate was
1662found, a pointer to the dn if found. If returned value is not @mynull{}, the value must
1663be free()'ed.
1664@end deftypefun
1665
1666@deftypefun {char *} MHD_cert_auth_get_alt_name (struct MHD_Connection *connection, int nametype, unsigned int index)
1667Get the alternative name of specified type from the client's certificate.
1668Return @mynull{} if the certificate doesn't contain a matching alternative name or if no
1669valid certificate was found, a pointer to the alternative name if found. If returned
1670value is not @mynull{}, the value must be free()'ed.
1671
1672@var{nametype} The requested name type (of type 'enum gnutls_x509_subject_alt_name_t')
1673
1674@var{index} The position of the alternative name if multiple names are matching the
1675requested type, 0 for the first matching name
1676@end deftypefun
1677
1678@c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1679
1680@c ------------------------------------------------------------
1566@node microhttpd-post 1681@node microhttpd-post
1567@chapter Adding a @code{POST} processor 1682@chapter Adding a @code{POST} processor
1568@cindex POST method 1683@cindex POST method
diff --git a/src/daemon/EXPORT.sym b/src/daemon/EXPORT.sym
index 28240e00..2d037cf0 100644
--- a/src/daemon/EXPORT.sym
+++ b/src/daemon/EXPORT.sym
@@ -27,3 +27,8 @@ MHD_get_version
27MHD_digest_auth_get_username 27MHD_digest_auth_get_username
28MHD_digest_auth_check 28MHD_digest_auth_check
29MHD_queue_auth_fail_response 29MHD_queue_auth_fail_response
30MHD_basic_auth_get_username_password
31MHD_queue_basic_auth_fail_response
32MHD_cert_auth_get_certificate
33MHD_cert_auth_get_dn
34MHD_cert_auth_get_alt_name
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 4a380b35..68ca4873 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -37,7 +37,8 @@ endif
37if ENABLE_DAUTH 37if ENABLE_DAUTH
38libmicrohttpd_la_SOURCES += \ 38libmicrohttpd_la_SOURCES += \
39 digestauth.c \ 39 digestauth.c \
40 md5.c md5.h 40 md5.c md5.h \
41 base64.c base64.h
41endif 42endif
42 43
43if ENABLE_HTTPS 44if ENABLE_HTTPS
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index 7a05037d..2695be66 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -2316,6 +2316,10 @@ MHD_get_connection_info (struct MHD_Connection *connection,
2316 if (connection->tls_session == NULL) 2316 if (connection->tls_session == NULL)
2317 return NULL; 2317 return NULL;
2318 return (const union MHD_ConnectionInfo *) &connection->tls_session; 2318 return (const union MHD_ConnectionInfo *) &connection->tls_session;
2319#if DAUTH_SUPPORT
2320 case MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT:
2321 return (const union MHD_ConnectionInfo *) MHD_cert_auth_get_certificate(connection);
2322#endif
2319#endif 2323#endif
2320 case MHD_CONNECTION_INFO_CLIENT_ADDRESS: 2324 case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
2321 return (const union MHD_ConnectionInfo *) &connection->addr; 2325 return (const union MHD_ConnectionInfo *) &connection->addr;
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 1fbd9e7b..d2373dc6 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -439,6 +439,19 @@ MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
439 gnutls_datum_t key; 439 gnutls_datum_t key;
440 gnutls_datum_t cert; 440 gnutls_datum_t cert;
441 441
442 if (daemon->https_mem_trust) {
443 cert.data = (unsigned char *) daemon->https_mem_trust;
444 cert.size = strlen(daemon->https_mem_trust);
445 if (gnutls_certificate_set_x509_trust_mem(daemon->x509_cred, &cert,
446 GNUTLS_X509_FMT_PEM) < 0) {
447#if HAVE_MESSAGES
448 MHD_DLOG(daemon,
449 "Bad trust certificate format\n");
450#endif
451 return -1;
452 }
453 }
454
442 /* certificate & key loaded from memory */ 455 /* certificate & key loaded from memory */
443 if (daemon->https_mem_cert && daemon->https_mem_key) 456 if (daemon->https_mem_cert && daemon->https_mem_key)
444 { 457 {
@@ -987,6 +1000,10 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
987 gnutls_transport_set_push_function (connection->tls_session, 1000 gnutls_transport_set_push_function (connection->tls_session,
988 (gnutls_push_func) & 1001 (gnutls_push_func) &
989 send_param_adapter); 1002 send_param_adapter);
1003
1004 if (daemon->https_mem_trust){
1005 gnutls_certificate_server_set_request(connection->tls_session, GNUTLS_CERT_REQUEST);
1006 }
990 } 1007 }
991#endif 1008#endif
992 1009
@@ -1058,6 +1075,8 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
1058#if HTTPS_SUPPORT 1075#if HTTPS_SUPPORT
1059 if (pos->tls_session != NULL) 1076 if (pos->tls_session != NULL)
1060 gnutls_deinit (pos->tls_session); 1077 gnutls_deinit (pos->tls_session);
1078 if (pos->client_cert != NULL)
1079 gnutls_x509_crt_deinit (pos->client_cert);
1061#endif 1080#endif
1062 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); 1081 MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
1063 if (pos->response != NULL) 1082 if (pos->response != NULL)
@@ -1474,6 +1493,16 @@ parse_options_va (struct MHD_Daemon *daemon,
1474 opt); 1493 opt);
1475#endif 1494#endif
1476 break; 1495 break;
1496 case MHD_OPTION_HTTPS_MEM_TRUST:
1497 if (0 != (daemon->options & MHD_USE_SSL))
1498 daemon->https_mem_trust = va_arg (ap, const char *);
1499#if HAVE_MESSAGES
1500 else
1501 FPRINTF (stderr,
1502 "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not set\n",
1503 opt);
1504#endif
1505 break;
1477 case MHD_OPTION_HTTPS_CRED_TYPE: 1506 case MHD_OPTION_HTTPS_CRED_TYPE:
1478 daemon->cred_type = va_arg (ap, gnutls_credentials_type_t); 1507 daemon->cred_type = va_arg (ap, gnutls_credentials_type_t);
1479 break; 1508 break;
@@ -1561,6 +1590,7 @@ parse_options_va (struct MHD_Daemon *daemon,
1561 case MHD_OPTION_SOCK_ADDR: 1590 case MHD_OPTION_SOCK_ADDR:
1562 case MHD_OPTION_HTTPS_MEM_KEY: 1591 case MHD_OPTION_HTTPS_MEM_KEY:
1563 case MHD_OPTION_HTTPS_MEM_CERT: 1592 case MHD_OPTION_HTTPS_MEM_CERT:
1593 case MHD_OPTION_HTTPS_MEM_TRUST:
1564 case MHD_OPTION_HTTPS_PRIORITIES: 1594 case MHD_OPTION_HTTPS_PRIORITIES:
1565 case MHD_OPTION_ARRAY: 1595 case MHD_OPTION_ARRAY:
1566 if (MHD_YES != parse_options (daemon, 1596 if (MHD_YES != parse_options (daemon,
@@ -1606,8 +1636,8 @@ parse_options_va (struct MHD_Daemon *daemon,
1606 break; 1636 break;
1607 default: 1637 default:
1608#if HAVE_MESSAGES 1638#if HAVE_MESSAGES
1609 if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) && 1639 if (((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
1610 (opt <= MHD_OPTION_HTTPS_PRIORITIES)) 1640 (opt <= MHD_OPTION_HTTPS_PRIORITIES)) || (opt == MHD_OPTION_HTTPS_MEM_TRUST))
1611 { 1641 {
1612 FPRINTF (stderr, 1642 FPRINTF (stderr,
1613 "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n", 1643 "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
diff --git a/src/daemon/digestauth.c b/src/daemon/digestauth.c
index b2be0d9d..c0d9abc0 100644
--- a/src/daemon/digestauth.c
+++ b/src/daemon/digestauth.c
@@ -19,13 +19,15 @@
19 19
20/** 20/**
21 * @file digestauth.c 21 * @file digestauth.c
22 * @brief Implements HTTP/1.1 Digest Auth according to RFC2617 22 * @brief Implements various HTTP authentication methods
23 * @author Amr Ali 23 * @author Amr Ali
24 * @author Matthieu Speder
24 */ 25 */
25 26
26#include "platform.h" 27#include "platform.h"
27#include "internal.h" 28#include "internal.h"
28#include "md5.h" 29#include "md5.h"
30#include "base64.h"
29 31
30#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE) 32#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
31 33
@@ -35,6 +37,11 @@
35#define _BASE "Digest " 37#define _BASE "Digest "
36 38
37/** 39/**
40 * Beginning string for any valid Basic authentication header.
41 */
42#define _BASIC_BASE "Basic "
43
44/**
38 * Maximum length of a username for digest authentication. 45 * Maximum length of a username for digest authentication.
39 */ 46 */
40#define MAX_USERNAME_LENGTH 128 47#define MAX_USERNAME_LENGTH 128
@@ -636,5 +643,218 @@ MHD_queue_auth_fail_response(struct MHD_Connection *connection,
636 return ret; 643 return ret;
637} 644}
638 645
646/**
647 * Get the username and password from the basic authorization header sent by the client
648 *
649 * @param connection The MHD connection structure
650 * @param password a pointer for the password
651 * @return NULL if no username could be found, a pointer
652 * to the username if found
653 */
654char *
655MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
656 char** password) {
657 size_t len;
658 const char *header;
659 char *decode;
660 const char *separator;
661 char *user;
662
663 header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND,
664 MHD_HTTP_HEADER_AUTHORIZATION);
665 if (header == NULL)
666 return NULL;
667 if (strncmp(header, _BASIC_BASE, strlen(_BASIC_BASE)) != 0)
668 return NULL;
669 header += strlen(_BASIC_BASE);
670 decode = BASE64Decode(header);
671 if (decode == NULL) {
672#if HAVE_MESSAGES
673 MHD_DLOG(connection->daemon, "Error decoding basic authentication\n");
674#endif
675 return NULL;
676 }
677 /* Find user:password pattern */
678 separator = strstr(decode, ":");
679 if (separator == NULL) {
680#if HAVE_MESSAGES
681 MHD_DLOG(connection->daemon,
682 "Basic authentication doesn't contain ':' separator\n");
683#endif
684 free(decode);
685 return NULL;
686 }
687 user = strndup(decode, separator - decode);
688 if (password != NULL) {
689 *password = strdup(separator + 1);
690 }
691 free(decode);
692 return user;
693}
694
695/**
696 * Queues a response to request basic authentication from the client
697 *
698 * @param connection The MHD connection structure
699 * @param realm the realm presented to the client
700 * @return MHD_YES on success, MHD_NO otherwise
701 */
702int MHD_queue_basic_auth_fail_response(struct MHD_Connection *connection,
703 const char *realm, struct MHD_Response *response) {
704 int ret;
705 size_t hlen = strlen(realm) + sizeof("Basic realm=\"\"");
706 char header[hlen];
707 snprintf(header, sizeof(header), "Basic realm=\"%s\"", realm);
708 ret = MHD_add_response_header(response, MHD_HTTP_HEADER_WWW_AUTHENTICATE,
709 header);
710 if (MHD_YES == ret)
711 ret = MHD_queue_response(connection, MHD_HTTP_UNAUTHORIZED, response);
712 return ret;
713}
714
715#if HTTPS_SUPPORT
716
717/**
718 * Get the client's certificate
719 *
720 * @param connection The MHD connection structure
721 * @return NULL if no valid client certificate could be found, a pointer
722 * to the certificate if found
723 */
724void*
725MHD_cert_auth_get_certificate(struct MHD_Connection *connection) {
726
727 if (connection->client_cert == NULL && connection->client_cert_status == 0) {
728 if (connection->tls_session == NULL) {
729 connection->client_cert_status = GNUTLS_CERT_INVALID;
730 return NULL;
731 }
732
733 if (gnutls_certificate_verify_peers2(connection->tls_session,
734 &connection->client_cert_status)) {
735 connection->client_cert_status = GNUTLS_CERT_INVALID;
736 return NULL;
737 }
738
739 unsigned int listsize;
740 const gnutls_datum_t * pcert = gnutls_certificate_get_peers(
741 connection->tls_session, &listsize);
742 if (pcert == NULL || listsize == 0) {
743#if HAVE_MESSAGES
744 MHD_DLOG(connection->daemon,
745 "Failed to retrieve client certificate chain\n");
746#endif
747 connection->client_cert_status = GNUTLS_CERT_INVALID;
748 return NULL;
749 }
750
751 if (gnutls_x509_crt_init(&connection->client_cert)) {
752#if HAVE_MESSAGES
753 MHD_DLOG(connection->daemon,
754 "Failed to initialize client certificate\n");
755#endif
756 connection->client_cert = NULL;
757 connection->client_cert_status = GNUTLS_CERT_INVALID;
758 return NULL;
759 }
760 if (gnutls_x509_crt_import(connection->client_cert, &pcert[0],
761 GNUTLS_X509_FMT_DER)) {
762#if HAVE_MESSAGES
763 MHD_DLOG(connection->daemon,
764 "Failed to import client certificate\n");
765#endif
766 gnutls_x509_crt_deinit(connection->client_cert);
767 connection->client_cert = NULL;
768 connection->client_cert_status = GNUTLS_CERT_INVALID;
769 return NULL;
770 }
771 }
772
773 return connection->client_cert;
774}
775
776/**
777 * Get the distinguished name from the client's certificate
778 *
779 * @param connection The MHD connection structure
780 * @return NULL if no dn or certificate could be found, a pointer
781 * to the dn if found
782 */
783char *
784MHD_cert_auth_get_dn(struct MHD_Connection *connection) {
785
786 char* buf;
787 size_t lbuf = 0;
788
789 gnutls_x509_crt_t cert = MHD_cert_auth_get_certificate(connection);
790 if (cert == NULL)
791 return NULL;
792
793 gnutls_x509_crt_get_dn(cert, NULL, &lbuf);
794 buf = malloc(lbuf);
795 if (buf == NULL) {
796#if HAVE_MESSAGES
797 MHD_DLOG(connection->daemon,
798 "Failed to allocate memory for certificate dn\n");
799#endif
800 return NULL;
801 }
802 gnutls_x509_crt_get_dn(cert, buf, &lbuf);
803 return buf;
804
805}
806
807/**
808 * Get the alternative name of specified type from the client's certificate
809 *
810 * @param connection The MHD connection structure
811 * @param nametype The requested name type
812 * @param index The position of the alternative name if multiple names are
813 * matching the requested type, 0 for the first matching name
814 * @return NULL if no matching alternative name could be found, a pointer
815 * to the alternative name if found
816 */
817char *
818MHD_cert_auth_get_alt_name(struct MHD_Connection *connection, int nametype, unsigned int index) {
819
820 char* buf;
821 size_t lbuf;
822 unsigned int seq = 0;
823 unsigned int subseq = 0;
824 int result;
825 unsigned int type;
826
827 gnutls_x509_crt_t cert = MHD_cert_auth_get_certificate(connection);
828 if (cert == NULL)
829 return NULL;
830
831 for (;; seq++) {
832 lbuf = 0;
833 result = gnutls_x509_crt_get_subject_alt_name2(cert, seq, NULL, &lbuf,
834 &type, NULL);
835 if (result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
836 return NULL;
837 if (type != nametype)
838 continue;
839 if (subseq != index) {
840 subseq++;
841 continue;
842 }
843 buf = malloc(lbuf);
844 if (buf == NULL) {
845#if HAVE_MESSAGES
846 MHD_DLOG(connection->daemon,
847 "Failed to allocate memory for certificate alt name\n");
848#endif
849 return NULL;
850 }
851 gnutls_x509_crt_get_subject_alt_name2(cert, seq, buf, &lbuf, NULL, NULL);
852 return buf;
853
854 }
855
856}
857
858#endif /* HTTPS */
639 859
640/* end of digestauth.c */ 860/* end of digestauth.c */
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
index 328c8433..a156d988 100644
--- a/src/daemon/internal.h
+++ b/src/daemon/internal.h
@@ -705,6 +705,17 @@ struct MHD_Connection
705 * Memory location to return for protocol session info. 705 * Memory location to return for protocol session info.
706 */ 706 */
707 int cipher; 707 int cipher;
708
709 /**
710 * Validation status of client's certificate.
711 */
712 gnutls_certificate_status_t client_cert_status;
713
714 /**
715 * Client's certificate.
716 */
717 gnutls_x509_crt_t client_cert;
718
708#endif 719#endif
709}; 720};
710 721
@@ -920,6 +931,11 @@ struct MHD_Daemon
920 */ 931 */
921 const char *https_mem_cert; 932 const char *https_mem_cert;
922 933
934 /**
935 * Pointer to our SSL/TLS certificate authority (in ASCII) in memory.
936 */
937 const char *https_mem_trust;
938
923#endif 939#endif
924 940
925#ifdef DAUTH_SUPPORT 941#ifdef DAUTH_SUPPORT
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index e97e1abd..f1256149 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -580,9 +580,14 @@ enum MHD_OPTION
580 * Desired size of the stack for threads created by MHD. Followed 580 * Desired size of the stack for threads created by MHD. Followed
581 * by an argument of type 'size_t'. Use 0 for system 'default'. 581 * by an argument of type 'size_t'. Use 0 for system 'default'.
582 */ 582 */
583 MHD_OPTION_THREAD_STACK_SIZE = 19 583 MHD_OPTION_THREAD_STACK_SIZE = 19,
584
585 584
585 /**
586 * Memory pointer for the certificate (ca.pem) to be used by the
587 * HTTPS daemon for client authentification.
588 * This option should be followed by a "const char*" argument.
589 */
590 MHD_OPTION_HTTPS_MEM_TRUST =20
586}; 591};
587 592
588 593
@@ -719,7 +724,12 @@ enum MHD_ConnectionInfoType
719 /** 724 /**
720 * Get the GNUTLS session handle. 725 * Get the GNUTLS session handle.
721 */ 726 */
722 MHD_CONNECTION_INFO_GNUTLS_SESSION 727 MHD_CONNECTION_INFO_GNUTLS_SESSION,
728
729 /**
730 * Get the GNUTLS client certificate handle.
731 */
732 MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT
723}; 733};
724 734
725/** 735/**
@@ -1430,6 +1440,65 @@ MHD_queue_auth_fail_response (struct MHD_Connection *connection,
1430 int signal_stale); 1440 int signal_stale);
1431 1441
1432 1442
1443/**
1444 * Get the username and password from the basic authorization header sent by the client
1445 *
1446 * @param connection The MHD connection structure
1447 * @param password a pointer for the password
1448 * @return NULL if no username could be found, a pointer
1449 * to the username if found
1450 */
1451char *
1452MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
1453 char** password);
1454
1455/**
1456 * Queues a response to request basic authentication from the client
1457 *
1458 * @param connection The MHD connection structure
1459 * @param realm the realm presented to the client
1460 * @return MHD_YES on success, MHD_NO otherwise
1461 */
1462int
1463MHD_queue_basic_auth_fail_response(struct MHD_Connection *connection,
1464 const char *realm,
1465 struct MHD_Response *response);
1466
1467/**
1468 * Get the client's certificate
1469 *
1470 * @param connection The MHD connection structure
1471 * @return NULL if no valid client certificate could be found, a pointer
1472 * to the certificate if found
1473 */
1474void*
1475MHD_cert_auth_get_certificate(struct MHD_Connection *connection);
1476
1477/**
1478 * Get the distinguished name from the client's certificate
1479 *
1480 * @param connection The MHD connection structure
1481 * @return NULL if no dn or certificate could be found, a pointer
1482 * to the dn if found
1483 */
1484char *
1485MHD_cert_auth_get_dn(struct MHD_Connection *connection);
1486
1487/**
1488 * Get the alternative name of specified type from the client's certificate
1489 *
1490 * @param connection The MHD connection structure
1491 * @param nametype The requested name type
1492 * @param index The position of the alternative name if multiple names are
1493 * matching the requested type, 0 for the first matching name
1494 * @return NULL if no matching alternative name could be found, a pointer
1495 * to the alternative name if found
1496 */
1497char *
1498MHD_cert_auth_get_alt_name(struct MHD_Connection *connection,
1499 int nametype,
1500 unsigned int index);
1501
1433/* ********************** generic query functions ********************** */ 1502/* ********************** generic query functions ********************** */
1434 1503
1435/** 1504/**
@@ -1454,6 +1523,11 @@ union MHD_ConnectionInfo
1454 void * /* gnutls_session_t */ tls_session; 1523 void * /* gnutls_session_t */ tls_session;
1455 1524
1456 /** 1525 /**
1526 * GNUtls client certificate handle, of type "gnutls_x509_crt_t".
1527 */
1528 void * /* gnutls_x509_crt_t */ client_cert;
1529
1530 /**
1457 * Address information for the client. 1531 * Address information for the client.
1458 */ 1532 */
1459 struct sockaddr_in * client_addr; 1533 struct sockaddr_in * client_addr;