diff options
Diffstat (limited to 'tcpd')
| -rw-r--r-- | tcpd/configure.ac | 7 | ||||
| -rw-r--r-- | tcpd/libcouriertls.c | 193 | ||||
| -rw-r--r-- | tcpd/tlsclient.c | 8 | ||||
| -rw-r--r-- | tcpd/tlsclient.h | 2 | 
4 files changed, 176 insertions, 34 deletions
| diff --git a/tcpd/configure.ac b/tcpd/configure.ac index 8f6d1fc..872a0ad 100644 --- a/tcpd/configure.ac +++ b/tcpd/configure.ac @@ -165,6 +165,13 @@ fi  dnl Checks for library functions. +PKG_CHECK_MODULES(LIBIDN, libidn >= 0.0.0, [libidn=yes], [libidn=no]) + +if test "$libidn" != "yes" +then +	AC_MSG_ERROR([libidn not found]) +fi +  AC_CHECK_FUNCS(setpgrp setpgid)  AC_CHECK_FUNC(setpgrp,  	[ diff --git a/tcpd/libcouriertls.c b/tcpd/libcouriertls.c index d62d722..1915ee0 100644 --- a/tcpd/libcouriertls.c +++ b/tcpd/libcouriertls.c @@ -9,6 +9,7 @@  #include	"libcouriertls.h"  #include	<openssl/rand.h>  #include	<openssl/x509.h> +#include	<openssl/x509v3.h>  #include	"tlscache.h"  #include	"rfc1035/rfc1035.h"  #include	"soxwrap/soxwrap.h" @@ -21,6 +22,7 @@  #include	<stdlib.h>  #include	<ctype.h>  #include	<netdb.h> +#include	<idna.h>  #if HAVE_DIRENT_H  #include <dirent.h>  #define NAMLEN(dirent) strlen((dirent)->d_name) @@ -140,38 +142,141 @@ static int ssl_verify_callback(int goodcert, X509_STORE_CTX *x509)  	return (1);  } +static int hostmatch_utf8(const char *a, const char *b) +{ +	while (*a || *b) +	{ +		char ca=*a; +		char cb=*b; + +		if (ca >= 'A' && ca <= 'Z') +			ca += 'a'-'A'; +		if (cb >= 'A' && cb <= 'Z') +			cb += 'a'-'A'; +		if (ca != cb) +			return 0; + +		++a; +		++b; +	} +	return 1; +} + +static int hostmatch(const struct tls_info *info, const char *domain) +{ +	const char *p=domain; +	const char *verify_domain=info->peer_verify_domain; +	char *idn_domain1; +	char *idn_domain2; +	int rc; + +	if (*p == '*') +	{ +		++p; + +		if (*p != '.') +			return 0; + +		while (*verify_domain) +		{ +			if (*verify_domain++ == '.') +				break; +		} +	} + +	if (idna_to_unicode_8z8z(info->peer_verify_domain, &idn_domain1, 0) +	    != IDNA_SUCCESS) +		idn_domain1=0; + +	if (idna_to_unicode_8z8z(p, &idn_domain2, 0) +	    != IDNA_SUCCESS) +		idn_domain2=0; + +	rc=hostmatch_utf8(idn_domain1 ? idn_domain1:info->peer_verify_domain, +			  idn_domain2 ? idn_domain2:p); + +	if (idn_domain1) +		free(idn_domain1); +	if (idn_domain2) +		free(idn_domain2); +	return rc; +} + +static int verifypeer1(const struct tls_info *info, X509 *x, +		       STACK_OF(GENERAL_NAME) *subject_alt_names); +  static int verifypeer(const struct tls_info *info, SSL *ssl)  {  	X509 *x=NULL; -	X509_NAME *subj=NULL; -	int nentries, j; -	char domain[256]; -	char *p; -	char errmsg[1000]; +	int rc; +	STACK_OF(GENERAL_NAME) *subject_alt_names;  	if (!info->peer_verify_domain)  		return (1); -	if (info->isserver) -	{ -		x=SSL_get_peer_certificate(ssl); +	if (SSL_get_verify_result(ssl) != X509_V_OK) +		return (1); -		if (x) -			subj=X509_get_subject_name(x); -	} -	else +	x=SSL_get_peer_certificate(ssl); + +	if (!x) +		return (0); + +	subject_alt_names= +		X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + +	rc=verifypeer1(info, x, subject_alt_names); + +	if (subject_alt_names) +		GENERAL_NAMES_free(subject_alt_names); + +	X509_free(x); + +	return rc; +} + +static int verifypeer1(const struct tls_info *info, X509 *x, +		       STACK_OF(GENERAL_NAME) *subject_alt_names) +{ +	X509_NAME *subj=NULL; +	int nentries, j; +	char domain[256]; +	char errmsg[1000]; + +	if(subject_alt_names)  	{ -		STACK_OF(X509) *peer_cert_chain=SSL_get_peer_cert_chain(ssl); +		int n=sk_GENERAL_NAME_num(subject_alt_names); +		int i; -		if (peer_cert_chain && sk_X509_num(peer_cert_chain) > 0) +		for (i=0; i<n; i++)  		{ -			X509 *xx=sk_X509_value(peer_cert_chain, 0); +			const GENERAL_NAME *gn= +				sk_GENERAL_NAME_value(subject_alt_names, i); +			const char *str; +			int l; -			if (xx) -				subj=X509_get_subject_name(xx); +			if (gn->type != GEN_DNS) +				continue; + +#ifdef HAVE_OPENSSL110 +			str = (const char *)ASN1_STRING_get0_data(gn->d.ia5); +#else +			str = (const char *)ASN1_STRING_data(gn->d.ia5); +#endif +			l=ASN1_STRING_length(gn->d.ia5); + +			if (l >= sizeof(domain)-1) +				l=sizeof(domain)-1; + +			memcpy(domain, str, l); +			domain[l]=0; + +			if (hostmatch(info, domain)) +				return 1;  		}  	} +	subj=X509_get_subject_name(x);  	nentries=0;  	if (subj) @@ -216,23 +321,8 @@ static int verifypeer(const struct tls_info *info, SSL *ssl)  		}  	} -	if (x) -		X509_free(x); -	p=domain; - -	if (*p == '*') -	{ -		int	pl, l; - -		pl=strlen(++p); -		l=strlen(info->peer_verify_domain); - -		if (*p == '.' && pl <= l && -		    strcasecmp(info->peer_verify_domain+l-pl, p) == 0) -			return (1); -	} -	else if (strcasecmp(info->peer_verify_domain, p) == 0) -		return (1); +	if (domain[0] && hostmatch(info, domain)) +		return 1;  	strcpy(errmsg, "couriertls: Mismatched SSL certificate: CN=");  	strcat(errmsg, domain); @@ -1474,6 +1564,8 @@ static void dump_x509(X509 *x509,  	X509_NAME *subj=X509_get_subject_name(x509);  	int nentries, j;  	time_t timestamp; +	STACK_OF(GENERAL_NAME) *subject_alt_names; +  	static const char gcc_shutup[]="%Y-%m-%d %H:%M:%S";  	if (!subj) @@ -1520,6 +1612,39 @@ static void dump_x509(X509 *x509,  	}  	(*dump_func)("\n", 1, dump_arg); +	subject_alt_names= +		X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL); + +	if (subject_alt_names) +	{ +		int n=sk_GENERAL_NAME_num(subject_alt_names); +		int i; + +		for (i=0; i<n; i++) +		{ +			const GENERAL_NAME *gn= +				sk_GENERAL_NAME_value(subject_alt_names, i); +			const char *domain; +			int l; + +			if (gn->type != GEN_DNS) +				continue; + +#ifdef HAVE_OPENSSL110 +			domain = (const char *)ASN1_STRING_get0_data(gn->d.ia5); +#else +			domain = (const char *)ASN1_STRING_data(gn->d.ia5); +#endif +			l=ASN1_STRING_length(gn->d.ia5); + +			(*dump_func)("Subject-Alt-Name-DNS: ", -1, dump_arg); +			(*dump_func)(domain, l, dump_arg); +			(*dump_func)("\n", -1, dump_arg); +		} + +		GENERAL_NAMES_free(subject_alt_names); +	} +  	timestamp=asn1toTime(X509_get_notBefore(x509));  	if (timestamp) diff --git a/tcpd/tlsclient.c b/tcpd/tlsclient.c index 7efa574..c7be1f3 100644 --- a/tcpd/tlsclient.c +++ b/tcpd/tlsclient.c @@ -379,6 +379,14 @@ static int do_couriertls_start(char **args, struct couriertls_info *cinfo)  		if (!s || !*s)  			s="couriertls"; +		if (cinfo->override_vars) +		{ +			size_t i; + +			for (i=0; cinfo->override_vars[i]; ++i) +				putenv(cinfo->override_vars[i]); +		} +  		execv(s, argvec);  		fprintf(fp, "500 Unable to start couriertls: %s\n",  			strerror(errno)); diff --git a/tcpd/tlsclient.h b/tcpd/tlsclient.h index b8eadbc..b624209 100644 --- a/tcpd/tlsclient.h +++ b/tcpd/tlsclient.h @@ -32,6 +32,8 @@ struct couriertls_info {  	size_t x509info_len;  	size_t x509info_size; +	char **override_vars; +  	struct tls_subject *first_subject;  	const char *cipher; | 
