summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--imap/ChangeLog4
-rw-r--r--imap/imapd-ssl.dist.in.git35
-rw-r--r--imap/pop3d-ssl.dist.in.git35
-rw-r--r--tcpd/configure.ac17
-rw-r--r--tcpd/libcouriergnutls.c20
-rw-r--r--tcpd/libcouriertls.c79
6 files changed, 137 insertions, 53 deletions
diff --git a/imap/ChangeLog b/imap/ChangeLog
index 660967b..f3ffcca 100644
--- a/imap/ChangeLog
+++ b/imap/ChangeLog
@@ -1,3 +1,7 @@
+2016-03-03 Sam Varshavchik <mrsam@courier-mta.com>
+
+ * libs/tcpd/libcouriertls.c: Add support for TLS SNI.
+
2016-01-22 Sam Varshavchik <mrsam@courier-mta.com>
* imaplogin.c (starttls): flush stdin after negotiating STARTTLS.
diff --git a/imap/imapd-ssl.dist.in.git b/imap/imapd-ssl.dist.in.git
index 7fede5d..20620cc 100644
--- a/imap/imapd-ssl.dist.in.git
+++ b/imap/imapd-ssl.dist.in.git
@@ -5,7 +5,7 @@
# Do not alter lines that begin with ##, they are used when upgrading
# this configuration.
#
-# Copyright 2000 - 2013 Double Precision, Inc. See COPYING for
+# Copyright 2000 - 2016 Double Precision, Inc. See COPYING for
# distribution information.
#
# This configuration file sets various options for the Courier-IMAP server
@@ -220,30 +220,29 @@ COURIERTLS=@bindir@/couriertls
# treated as confidential, and must not be world-readable. Set TLS_CERTFILE
# instead of TLS_DHCERTFILE if this is a garden-variety certificate
#
-# VIRTUAL HOSTS (servers only):
+# VIRTUAL HOSTS ON THE SAME IP ADDRESS.
#
-# Due to technical limitations in the original SSL/TLS protocol, a dedicated
-# IP address is required for each virtual host certificate. If you have
-# multiple certificates, install each certificate file as
+# Install each certificate $TLS_CERTFILE.domain, so if TLS_CERTFILE is set to
+# /etc/certificate.pem, then you'll need to install the actual certificate
+# files as /etc/certificate.pem.www.example.com,
+# /etc/certificate.pem.www.domain.com and so on. Then, create a link from
+# $TLS_CERTFILE to whichever certificate you consider to be the main one,
+# for example:
+# /etc/certificate.pem => /etc/certificate.pem.www.example.com
+#
+# IP-BASED VIRTUAL HOSTS:
+#
+# There may be a need to support older SSL/TLS client that don't support
+# virtual hosts on the same IP address, and require a dedicated IP address
+# for each SSL/TLS host. If so, install each certificate file as
# $TLS_CERTFILE.aaa.bbb.ccc.ddd, where "aaa.bbb.ccc.ddd" is the IP address
# for the certificate's domain name. So, if TLS_CERTFILE is set to
# /etc/certificate.pem, then you'll need to install the actual certificate
# files as /etc/certificate.pem.192.168.0.2, /etc/certificate.pem.192.168.0.3
# and so on, for each IP address.
#
-# GnuTLS only (servers only):
-#
-# GnuTLS implements a new TLS extension that eliminates the need to have a
-# dedicated IP address for each SSL/TLS domain name. Install each certificate
-# as $TLS_CERTFILE.domain, so if TLS_CERTFILE is set to /etc/certificate.pem,
-# then you'll need to install the actual certificate files as
-# /etc/certificate.pem.host1.example.com, /etc/certificate.pem.host2.example.com
-# and so on.
-#
-# Note that this TLS extension also requires a corresponding support in the
-# client. Older SSL/TLS clients may not support this feature.
-#
-# This is an experimental feature.
+# In all cases, $TLS_CERTFILE needs to be linked to one of the existing
+# certificate files.
TLS_CERTFILE=@certsdir@/imapd.pem
diff --git a/imap/pop3d-ssl.dist.in.git b/imap/pop3d-ssl.dist.in.git
index 89d6e7d..70ee341 100644
--- a/imap/pop3d-ssl.dist.in.git
+++ b/imap/pop3d-ssl.dist.in.git
@@ -5,7 +5,7 @@
# Do not alter lines that begin with ##, they are used when upgrading
# this configuration.
#
-# Copyright 2000-2013 Double Precision, Inc. See COPYING for
+# Copyright 2000-2016 Double Precision, Inc. See COPYING for
# distribution information.
#
# This configuration file sets various options for the Courier-IMAP server
@@ -186,30 +186,29 @@ COURIERTLS=@bindir@/couriertls
# treated as confidential, and must not be world-readable. Set TLS_CERTFILE
# instead of TLS_DHCERTFILE if this is a garden-variety certificate
#
-# VIRTUAL HOSTS (servers only):
+# VIRTUAL HOSTS ON THE SAME IP ADDRESS.
#
-# Due to technical limitations in the original SSL/TLS protocol, a dedicated
-# IP address is required for each virtual host certificate. If you have
-# multiple certificates, install each certificate file as
+# Install each certificate $TLS_CERTFILE.domain, so if TLS_CERTFILE is set to
+# /etc/certificate.pem, then you'll need to install the actual certificate
+# files as /etc/certificate.pem.www.example.com,
+# /etc/certificate.pem.www.domain.com and so on. Then, create a link from
+# $TLS_CERTFILE to whichever certificate you consider to be the main one,
+# for example:
+# /etc/certificate.pem => /etc/certificate.pem.www.example.com
+#
+# IP-BASED VIRTUAL HOSTS:
+#
+# There may be a need to support older SSL/TLS client that don't support
+# virtual hosts on the same IP address, and require a dedicated IP address
+# for each SSL/TLS host. If so, install each certificate file as
# $TLS_CERTFILE.aaa.bbb.ccc.ddd, where "aaa.bbb.ccc.ddd" is the IP address
# for the certificate's domain name. So, if TLS_CERTFILE is set to
# /etc/certificate.pem, then you'll need to install the actual certificate
# files as /etc/certificate.pem.192.168.0.2, /etc/certificate.pem.192.168.0.3
# and so on, for each IP address.
#
-# GnuTLS only (servers only):
-#
-# GnuTLS implements a new TLS extension that eliminates the need to have a
-# dedicated IP address for each SSL/TLS domain name. Install each certificate
-# as $TLS_CERTFILE.domain, so if TLS_CERTFILE is set to /etc/certificate.pem,
-# then you'll need to install the actual certificate files as
-# /etc/certificate.pem.host1.example.com, /etc/certificate.pem.host2.example.com
-# and so on.
-#
-# Note that this TLS extension also requires a corresponding support in the
-# client. Older SSL/TLS clients may not support this feature.
-#
-# This is an experimental feature.
+# In all cases, $TLS_CERTFILE needs to be linked to one of the existing
+# certificate files.
TLS_CERTFILE=@certsdir@/pop3d.pem
diff --git a/tcpd/configure.ac b/tcpd/configure.ac
index 6ba8acf..447ba72 100644
--- a/tcpd/configure.ac
+++ b/tcpd/configure.ac
@@ -134,12 +134,12 @@ AC_SYS_LARGEFILE
AC_CACHE_CHECK([for socklen_t],
tcpd_cv_hassocklen_t,
-
+
AC_COMPILE_IFELSE([
AC_LANG_SOURCE( [
#include <sys/types.h>
#include <sys/socket.h>
-
+
socklen_t sl_t;
],[
accept(0, 0, &sl_t);
@@ -147,9 +147,9 @@ socklen_t sl_t;
tcpd_cv_hassocklen_t=yes,
tcpd_cv_hassocklen_t=no)
)
-
+
socklen_t="int"
-
+
if test $tcpd_cv_hassocklen_t = yes
then
:
@@ -510,6 +510,15 @@ RAND_pseudo_bytes(dummy, 1);
AC_CHECK_FUNCS(TLSv1_1_method TLSv1_2_method)
LIBS="$save_LIBS"
+ AC_TRY_COMPILE( [
+#include <openssl/ssl.h>
+],
+[
+SSL_get_servername((SSL *)0, TLSEXT_NAMETYPE_host_name);
+], [
+ AC_DEFINE_UNQUOTED(HAVE_OPENSSL_SNI,1,[ When OpenSSL supports SNI ])
+ ])
+
TLSLIBRARY="$LIBCOURIERTLSOPENSSL"
STARTTLS=couriertls$EXEEXT
BUILDLIBCOURIERTLS=libcouriertls.la
diff --git a/tcpd/libcouriergnutls.c b/tcpd/libcouriergnutls.c
index 20823a9..38b70ab 100644
--- a/tcpd/libcouriergnutls.c
+++ b/tcpd/libcouriergnutls.c
@@ -718,7 +718,7 @@ static int verify_client(ssl_handle ssl, int fd)
!gnutls_openpgp_key_check_hostname(cert,
ssl->info_cpy
.peer_verify_domain))
-
+
{
char *hostname;
size_t hostnamesiz=0;
@@ -784,7 +784,7 @@ static int dohandshake(ssl_handle ssl, int fd, fd_set *r, fd_set *w)
{
ssl->info_cpy.connect_interrupted=0;
-
+
if (verify_client(ssl, fd))
return -1;
@@ -1003,7 +1003,7 @@ static int get_server_cert(gnutls_session_t session,
for (p=vhost_buf; *p; p++)
if (*p == '/')
- *p='.';
+ *p='.'; /* Script kiddie check */
if (ssl->ctx->certfile)
certfilename=check_cert(ssl->ctx->certfile,
@@ -1273,7 +1273,7 @@ static int do_cache_remove(void *rec, size_t recsize, int *doupdate, void *arg)
}
return 0;
}
-
+
static int db_remove_func(void *dummy, gnutls_datum_t key)
{
tls_cache_walk(((ssl_handle)dummy)->info_cpy.tlscache,
@@ -1444,9 +1444,9 @@ ssl_handle tls_connect(ssl_context ctx, int fd)
gnutls_session_set_ptr(ssl->session, ssl);
gnutls_handshake_set_private_extensions(ssl->session, 1);
- gnutls_certificate_set_verify_flags(ssl->xcred,
+ gnutls_certificate_set_verify_flags(ssl->xcred,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT |
-
+
/*
GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_C
@@ -1567,7 +1567,7 @@ int tls_transfer(struct tls_transfer_info *t, ssl_handle ssl, int fd,
return 1;
}
-
+
t->shutdown_interrupted=0;
t->shutdown= -1;
return -1;
@@ -1717,7 +1717,7 @@ static const char *dump_dn(gnutls_x509_crt_t cert,
free(oidname);
return gnutls_strerror(rc);
}
-
+
vidx=0;
while (bufsiz=0,
@@ -1781,7 +1781,7 @@ static const char *dump_dn(gnutls_x509_crt_t cert,
++vidx;
}
}
-
+
free(oidval);
free(oidname);
return NULL;
@@ -1870,7 +1870,7 @@ static void dump_cipher_name(gnutls_session_t session,
gnutls_compression_method_t comp;
(*dump_func)(gnutls_kx_get_name(kx_algo), -1, dump_arg);
-
+
(*dump_func)("-", 1, dump_arg);
(*dump_func)(gnutls_certificate_type_get_name(gnutls_certificate_type_get(session)),
-1, dump_arg);
diff --git a/tcpd/libcouriertls.c b/tcpd/libcouriertls.c
index 9252c05..985c76e 100644
--- a/tcpd/libcouriertls.c
+++ b/tcpd/libcouriertls.c
@@ -1,5 +1,5 @@
/*
-** Copyright 2000-2014 Double Precision, Inc.
+** Copyright 2000-2016 Double Precision, Inc.
** See COPYING for distribution information.
*/
#include "config.h"
@@ -308,7 +308,24 @@ static void load_dh_params(SSL_CTX *ctx, const char *filename,
DH_free(dh);
}
else
- sslerror(info, filename, -1);
+ {
+ /*
+ ** If the certificate file does not have DH parameters,
+ ** swallow the error.
+ */
+
+ int err=ERR_peek_last_error();
+
+ if (ERR_GET_LIB(err) == ERR_LIB_PEM
+ && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
+ {
+ ERR_clear_error();
+ }
+ else
+ {
+ sslerror(info, filename, -1);
+ }
+ }
BIO_free(bio);
}
else
@@ -476,6 +493,47 @@ static int client_cert_cb(ssl_handle ssl, X509 **x509, EVP_PKEY **pkey)
return rc;
}
+static int server_cert_cb(ssl_handle ssl, int *ad, void *arg)
+{
+#ifdef HAVE_OPENSSL_SNI
+ struct tls_info *info=(struct tls_info *)SSL_get_app_data(ssl);
+ const char *servername=SSL_get_servername(ssl,
+ TLSEXT_NAMETYPE_host_name);
+ const char *certfile=safe_getenv(info, "TLS_CERTFILE");
+ int cert_file_flags=0;
+ char *buffer;
+ char *p;
+
+ if (!servername || !certfile)
+ return SSL_TLSEXT_ERR_OK;
+
+ buffer=malloc(strlen(certfile)+strlen(servername)+2);
+ if (!buffer)
+ {
+ nonsslerror(info, "malloc");
+ exit(1);
+ }
+
+ strcat(strcpy(buffer, certfile), ".");
+
+ p=buffer + strlen(buffer);
+
+ while ((*p=*servername) != 0)
+ {
+ if (*p == '/')
+ *p='.'; /* Script kiddie check */
+ ++p;
+ ++servername;
+ }
+
+ if (access(buffer, R_OK) == 0)
+ read_certfile(SSL_get_SSL_CTX(ssl), buffer, &cert_file_flags);
+
+ free(buffer);
+#endif
+ return SSL_TLSEXT_ERR_OK;
+}
+
SSL_CTX *tls_create(int isserver, const struct tls_info *info)
{
SSL_CTX *ctx;
@@ -691,8 +749,15 @@ SSL_CTX *tls_create(int isserver, const struct tls_info *info)
}
SSL_CTX_set_verify(ctx, get_peer_verify_level(info),
ssl_verify_callback);
- if (!isserver)
+
+ if (isserver)
+ {
+ SSL_CTX_set_tlsext_servername_callback(ctx, server_cert_cb);
+ }
+ else
+ {
SSL_CTX_set_client_cert_cb(ctx, client_cert_cb);
+ }
return (ctx);
}
@@ -997,6 +1062,14 @@ SSL *tls_connect(SSL_CTX *ctx, int fd)
{
SSL_set_connect_state(ssl);
+#ifdef HAVE_OPENSSL_SNI
+ if (info->peer_verify_domain)
+ {
+ fprintf(stderr, "Requesting %s\n", info->peer_verify_domain);
+ SSL_set_tlsext_host_name(ssl, info->peer_verify_domain);
+ }
+#endif
+
if ((rc=SSL_connect(ssl)) > 0)
{
if (!verifypeer(info, ssl))