From 296d760c2db224567fd3b9ba15280a43fe48a6ba Mon Sep 17 00:00:00 2001 From: Sam Varshavchik Date: Tue, 10 Dec 2019 20:36:35 -0500 Subject: 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. --- imap/configure.ac | 2 +- tcpd/configure.ac | 2 +- tcpd/libcouriertls.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 211 insertions(+), 12 deletions(-) diff --git a/imap/configure.ac b/imap/configure.ac index 9bf0201..6ac8577 100644 --- a/imap/configure.ac +++ b/imap/configure.ac @@ -4,7 +4,7 @@ dnl dnl Copyright 1998 - 2019 Double Precision, Inc. See COPYING for dnl distribution information. -AC_INIT(courier-imap, 5.0.8.20191205, [courier-users@lists.sourceforge.net]) +AC_INIT(courier-imap, 5.0.8.20191210, [courier-users@lists.sourceforge.net]) >confdefs.h # Kill PACKAGE_ macros diff --git a/tcpd/configure.ac b/tcpd/configure.ac index 872a0ad..08ba7d0 100644 --- a/tcpd/configure.ac +++ b/tcpd/configure.ac @@ -552,7 +552,7 @@ RAND_bytes(dummy, 1); ] ) LIBS="-lssl $LIBS" - AC_CHECK_FUNCS(TLSv1_1_method TLSv1_2_method) + AC_CHECK_FUNCS(TLSv1_1_method TLSv1_2_method X509_VERIFY_PARAM_set1_host) LIBS="$save_LIBS" AC_TRY_COMPILE( [ 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; itype != 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= 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) { -- cgit v1.2.3