diff options
| author | Sam Varshavchik | 2019-12-10 20:36:35 -0500 | 
|---|---|---|
| committer | Sam Varshavchik | 2019-12-10 20:39:04 -0500 | 
| commit | 296d760c2db224567fd3b9ba15280a43fe48a6ba (patch) | |
| tree | 48c3cb784c350f04329b5bd60b8f3f12c8ac4449 /tcpd/libcouriertls.c | |
| parent | eaa4c8f12c295b03d5034fc3d4ec1e45c86984af (diff) | |
| download | courier-libs-296d760c2db224567fd3b9ba15280a43fe48a6ba.tar.bz2 | |
Restore OpenSSL 1.1, and earlier support.
Restores code that c8115514b4830a668ce726b2fcb8ab4a3d438ec9 removed,
but make it conditionally compiled. Have configure.ac autodetect the
openssl version.
Correctly UTF8-ize SSL_set_tlsext_host_name()'s parameter.
Diffstat (limited to 'tcpd/libcouriertls.c')
| -rw-r--r-- | tcpd/libcouriertls.c | 219 | 
1 files changed, 209 insertions, 10 deletions
| diff --git a/tcpd/libcouriertls.c b/tcpd/libcouriertls.c index d4d1643..ac05caf 100644 --- a/tcpd/libcouriertls.c +++ b/tcpd/libcouriertls.c @@ -142,6 +142,7 @@ static int ssl_verify_callback(int goodcert, X509_STORE_CTX *x509)  	return (1);  } +#if HAVE_X509_VERIFY_PARAM_SET1_HOST  static int verifypeer(const struct tls_info *info, SSL *ssl)  {  	if (!info->peer_verify_domain) @@ -149,6 +150,199 @@ static int verifypeer(const struct tls_info *info, SSL *ssl)  	return SSL_get_verify_result(ssl) == X509_V_OK;  } +#else + +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; +	int rc; +	STACK_OF(GENERAL_NAME) *subject_alt_names; + +	if (!info->peer_verify_domain) +		return (1); + +	if (SSL_get_verify_result(ssl) != X509_V_OK) +		return (1); + +	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) +	{ +		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 *str; +			int l; + +			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) +		nentries=X509_NAME_entry_count(subj); + +	domain[0]=0; +	for (j=0; j<nentries; j++) +	{ +		const char *obj_name; +		X509_NAME_ENTRY *e; +		ASN1_OBJECT *o; +		ASN1_STRING *d; + +		int dlen; +		const unsigned char *ddata; + +		e=X509_NAME_get_entry(subj, j); +		if (!e) +			continue; + +		o=X509_NAME_ENTRY_get_object(e); +		d=X509_NAME_ENTRY_get_data(e); + +		if (!o || !d) +			continue; + +		obj_name=OBJ_nid2sn(OBJ_obj2nid(o)); + +		dlen=ASN1_STRING_length(d); +#ifdef HAVE_OPENSSL110 +		ddata=ASN1_STRING_get0_data(d); +#else +		ddata=ASN1_STRING_data(d); +#endif +		if (strcasecmp(obj_name, "CN") == 0) +		{ +			if (dlen >= sizeof(domain)-1) +				dlen=sizeof(domain)-1; + +			memcpy(domain, ddata, dlen); +			domain[dlen]=0; +		} +	} + +	if (domain[0] && hostmatch(info, domain)) +		return 1; + +	strcpy(errmsg, "couriertls: Mismatched SSL certificate: CN="); +	strcat(errmsg, domain); +	strcat(errmsg, " (expected "); +	strncat(errmsg, info->peer_verify_domain, 256); +	strcat(errmsg, ")"); +	(*info->tls_err_msg)(errmsg, info->app_data); +	return (0); +} +#endif  static void nonsslerror(const struct tls_info *info, const char *pfix)  { @@ -1083,32 +1277,37 @@ SSL *tls_connect(SSL_CTX *ctx, int fd)  	}  	else  	{ +		char *idn_domain1; + +		if (idna_to_unicode_8z8z(info->peer_verify_domain, +					 &idn_domain1, 0) +		    != IDNA_SUCCESS) +			idn_domain1=0; +  		SSL_set_connect_state(ssl);  #ifdef HAVE_OPENSSL_SNI  		if (info->peer_verify_domain)  		{ -			SSL_set_tlsext_host_name(ssl, info->peer_verify_domain); +			SSL_set_tlsext_host_name(ssl, +						 idn_domain1 ? idn_domain1 +						 : (char *) +						 info->peer_verify_domain);  		}  #endif +#if HAVE_X509_VERIFY_PARAM_SET1_HOST  		if (info->peer_verify_domain)  		{ -			char *idn_domain1; - -			if (idna_to_unicode_8z8z(info->peer_verify_domain, -						 &idn_domain1, 0) -			    != IDNA_SUCCESS) -				idn_domain1=0; -  			X509_VERIFY_PARAM *param = SSL_get0_param(ssl);  			X509_VERIFY_PARAM_set1_host(param,  						    idn_domain1 ?  						    idn_domain1 :  						    info->peer_verify_domain,  						    0); -			if (idn_domain1) -				free(idn_domain1);  		} +#endif +		if (idn_domain1) +			free(idn_domain1);  		if ((rc=SSL_connect(ssl)) > 0)  		{ | 
