diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | doc/microhttpd.texi | 131 | ||||
-rw-r--r-- | src/daemon/EXPORT.sym | 5 | ||||
-rw-r--r-- | src/daemon/Makefile.am | 3 | ||||
-rw-r--r-- | src/daemon/connection.c | 4 | ||||
-rw-r--r-- | src/daemon/daemon.c | 34 | ||||
-rw-r--r-- | src/daemon/digestauth.c | 222 | ||||
-rw-r--r-- | src/daemon/internal.h | 16 | ||||
-rw-r--r-- | src/include/microhttpd.h | 80 |
11 files changed, 489 insertions, 20 deletions
@@ -4,6 +4,7 @@ Nils Durner <durner@gnunet.org> (W32 port) | |||
4 | Sagie Amir (TLS/SSL support using GNUtls) | 4 | Sagie Amir (TLS/SSL support using GNUtls) |
5 | Richard Alimi <rich@velvetsea.net> (performance) | 5 | Richard Alimi <rich@velvetsea.net> (performance) |
6 | Amr Ali <amr.ali.cc@gmail.com> (digest authentication) | 6 | Amr Ali <amr.ali.cc@gmail.com> (digest authentication) |
7 | Matthieu Speder <mspeder@users.sourceforge.net> (basic authentication, client certificates) | ||
7 | 8 | ||
8 | Code contributions also came from: | 9 | Code contributions also came from: |
9 | Chris GauthierDickey <chrisg@cs.du.edu> | 10 | Chris GauthierDickey <chrisg@cs.du.edu> |
@@ -1,3 +1,6 @@ | |||
1 | Sat Dec 25 21:57:14 CET 2010 | ||
2 | Adding support for basic authentication and client SSL certificates. -MS | ||
3 | |||
1 | Thu Dec 23 15:40:36 CET 2010 | 4 | Thu 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) | |||
325 | AM_CONDITIONAL(ENABLE_HTTPS, test "$enable_https" = "yes") | 325 | AM_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 |
328 | AC_MSG_CHECKING(whether to support HTTP Digest authentication) | 328 | AC_MSG_CHECKING(whether to support HTTP basic and digest authentication) |
329 | AC_ARG_ENABLE([dauth], | 329 | AC_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 | ||
335 | if test "$enable_dauth" = "yes" | 335 | if test "$enable_dauth" = "yes" |
336 | then | 336 | then |
337 | AC_DEFINE([DAUTH_SUPPORT],[1],[include Digest Auth support]) | 337 | AC_DEFINE([DAUTH_SUPPORT],[1],[include basic and digest Auth support]) |
338 | else | 338 | else |
339 | AC_DEFINE([DAUTH_SUPPORT],[0],[disable Digest Auth support]) | 339 | AC_DEFINE([DAUTH_SUPPORT],[0],[disable basic and digest Auth support]) |
340 | fi | 340 | fi |
341 | AC_MSG_RESULT($enable_dauth) | 341 | AC_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 | |||
259 | corresponding format string for printing such a data type (without | 259 | corresponding format string for printing such a data type (without |
260 | the percent sign). | 260 | the 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. |
450 | This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_KEY'. | 449 | This 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 | ||
454 | Memory pointer to the CA certificate to be used by the | ||
455 | HTTPS daemon to authenticate and trust clients certificates. | ||
456 | This option should be followed by an "const char*" argument. | ||
457 | The presence of this option activates the request of certificate | ||
458 | to the client. The request to the client is marked optional, and | ||
459 | it is the responsability of the server to check the presence | ||
460 | of the certificate if needed. | ||
461 | Note that most browsers will only present a client certificate | ||
462 | only if they have one matching the specified CA, not sending | ||
463 | any 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 | |||
680 | Takes no extra arguments. Allows access to the underlying GNUtls session | 693 | Takes 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 | ||
697 | Allows access to the underlying GNUtls client certificate. | ||
698 | Equivalent to calling directly MHD_cert_auth_get_certificate. | ||
699 | Takes 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 | |||
1484 | Basic authentication uses a simple authentication method based | ||
1485 | on BASE64 algorithm. Username and password are exchanged in clear | ||
1486 | between the client and the server, so this method must only be used | ||
1487 | for non-sensitive content or when the session is protected with https. | ||
1488 | When using basic authentication @mhd{} will have access to the clear | ||
1489 | password, possibily allowing to create a chained authentication | ||
1490 | toward an external authentication server. | ||
1491 | |||
1492 | Digest authentication uses a one-way authentication method based | ||
1493 | on MD5 hash algorithm. Only the hash will transit over the network, | ||
1494 | hence protecting the user password. The nonce will prevent replay | ||
1495 | attacks. This method is appropriate for general use, especially | ||
1496 | when https is not used to encrypt the session. | ||
1497 | |||
1498 | Client certificate authentication uses a X.509 certificate from | ||
1499 | the client. This is the strongest authentication mechanism but it | ||
1500 | requires the use of https. Client certificate authentication can | ||
1501 | be used simultaneously with Basic or Digest Authentication in order | ||
1502 | to provide a two levels authentication (like for instance separate | ||
1503 | machine 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) | ||
1518 | Get the username and password from the basic authorization header sent by the client. | ||
1519 | Return @mynull{} if no username could be found, a pointer to the username if found. | ||
1520 | If 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{}. | ||
1523 | If 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) | ||
1527 | Queues a response to request basic authentication from the client. | ||
1528 | Return @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 | ||
1533 | client 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) |
1463 | Find and return a pointer to the username value from the request header. | 1543 | 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. | |||
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) |
1469 | Checks if the provided values in the WWW-Authenticate header are valid | 1549 | Checks if the provided values in the WWW-Authenticate header are valid |
1470 | and sound according to RFC2716. If valid return MHD_YES, otherwise return MHD_NO. | 1550 | and 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) |
1485 | Queues a response to request authentication from the client, | 1565 | Queues a response to request authentication from the client, |
1486 | return MHD_YES if successful, otherwise MHD_NO. | 1566 | return @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 |
1489 | that gets passed to the client and expected to be passed again to the server | 1571 | 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. | |||
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 |
1496 | indicate the invalidity of the nonce and no need to ask for authentication | 1578 | indicate the invalidity of the nonce and no need to ask for authentication |
1497 | parameters and only a new nonce gets generated. MHD_YES to generate a new | 1579 | parameters and only a new nonce gets generated. @code{MHD_YES} to generate a new |
1498 | nonce, MHD_NO to ask for authentication parameters. | 1580 | nonce, @code{MHD_NO} to ask for authentication parameters. |
1499 | @end deftypefun | 1581 | @end deftypefun |
1500 | 1582 | ||
1501 | Example: handling digest authentication requests and responses. | 1583 | Example: 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) | ||
1652 | Get the client's X.509 certificate. | ||
1653 | Return @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. | ||
1655 | The certificate is cached between calls for a same https session and must not but | ||
1656 | manually modified or free()'ed. | ||
1657 | @end deftypefun | ||
1658 | |||
1659 | @deftypefun {char *} MHD_cert_auth_get_dn (struct MHD_Connection *connection) | ||
1660 | Get the distinguished name from the client's certificate. | ||
1661 | Return @mynull{} if the certificate doesn't contain a dn or if no valid certificate was | ||
1662 | found, a pointer to the dn if found. If returned value is not @mynull{}, the value must | ||
1663 | be free()'ed. | ||
1664 | @end deftypefun | ||
1665 | |||
1666 | @deftypefun {char *} MHD_cert_auth_get_alt_name (struct MHD_Connection *connection, int nametype, unsigned int index) | ||
1667 | Get the alternative name of specified type from the client's certificate. | ||
1668 | Return @mynull{} if the certificate doesn't contain a matching alternative name or if no | ||
1669 | valid certificate was found, a pointer to the alternative name if found. If returned | ||
1670 | value 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 | ||
1675 | requested 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 | |||
27 | MHD_digest_auth_get_username | 27 | MHD_digest_auth_get_username |
28 | MHD_digest_auth_check | 28 | MHD_digest_auth_check |
29 | MHD_queue_auth_fail_response | 29 | MHD_queue_auth_fail_response |
30 | MHD_basic_auth_get_username_password | ||
31 | MHD_queue_basic_auth_fail_response | ||
32 | MHD_cert_auth_get_certificate | ||
33 | MHD_cert_auth_get_dn | ||
34 | MHD_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 | |||
37 | if ENABLE_DAUTH | 37 | if ENABLE_DAUTH |
38 | libmicrohttpd_la_SOURCES += \ | 38 | libmicrohttpd_la_SOURCES += \ |
39 | digestauth.c \ | 39 | digestauth.c \ |
40 | md5.c md5.h | 40 | md5.c md5.h \ |
41 | base64.c base64.h | ||
41 | endif | 42 | endif |
42 | 43 | ||
43 | if ENABLE_HTTPS | 44 | if 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 | */ | ||
654 | char * | ||
655 | MHD_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 | */ | ||
702 | int 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 | */ | ||
724 | void* | ||
725 | MHD_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 | */ | ||
783 | char * | ||
784 | MHD_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 | */ | ||
817 | char * | ||
818 | MHD_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 | */ | ||
1451 | char * | ||
1452 | MHD_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 | */ | ||
1462 | int | ||
1463 | MHD_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 | */ | ||
1474 | void* | ||
1475 | MHD_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 | */ | ||
1484 | char * | ||
1485 | MHD_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 | */ | ||
1497 | char * | ||
1498 | MHD_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; |