aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-12-25 20:58:06 +0000
committerChristian Grothoff <christian@grothoff.org>2010-12-25 20:58:06 +0000
commitfe4e71ecaa788e73582b7ee29d1835a3e3112be3 (patch)
treebf9b14af91d384796349cc9478a32452f623318c /src
parent65c3125ced95cc8f6d151f8c66e0d6a06255f04f (diff)
downloadlibmicrohttpd-fe4e71ecaa788e73582b7ee29d1835a3e3112be3.tar.gz
libmicrohttpd-fe4e71ecaa788e73582b7ee29d1835a3e3112be3.zip
client certs and basic auth support, unmodified patch from MS
Diffstat (limited to 'src')
-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
7 files changed, 357 insertions, 7 deletions
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;