]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
login proxy: Verify that remote hostname matches SSL cert, unless ssl=any-cert
authorTimo Sirainen <tss@iki.fi>
Tue, 8 Nov 2011 21:40:54 +0000 (23:40 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 8 Nov 2011 21:40:54 +0000 (23:40 +0200)
configure.in
src/lib-ssl-iostream/iostream-openssl.c
src/lib-ssl-iostream/iostream-openssl.h
src/login-common/Makefile.am
src/login-common/login-proxy.c
src/login-common/ssl-proxy-openssl.c
src/login-common/ssl-proxy.c
src/login-common/ssl-proxy.h

index 32f154c460e416335b425f8a45e66c998efab76d..fde242cb62ad27c1cd50e69bf59e66ff08ca151e 100644 (file)
@@ -2487,7 +2487,7 @@ else
   LIBDOVECOT_STORAGE_LAST='$(top_builddir)/src/lib-storage/list/libstorage_list.la $(top_builddir)/src/lib-storage/index/libstorage_index.la $(top_builddir)/src/lib-storage/libstorage.la $(top_builddir)/src/lib-index/libindex.la'
   LIBDOVECOT_STORAGE_FIRST='$(top_builddir)/src/lib-storage/libstorage_service.la $(top_builddir)/src/lib-storage/register/libstorage_register.la'
   LIBDOVECOT_STORAGE="$LIBDOVECOT_STORAGE_FIRST $LINKED_STORAGE_LIBS $LIBDOVECOT_STORAGE_LAST"
-  LIBDOVECOT_LOGIN='$(top_builddir)/src/login-common/liblogin.la'
+  LIBDOVECOT_LOGIN='$(top_builddir)/src/login-common/liblogin.la $(top_builddir)/src/lib-ssl-iostream/libssl_iostream.la'
   LIBDOVECOT_LDA='$(top_builddir)/src/lib-lda/liblda.la'
 fi
 LIBDOVECOT_SQL='$(top_builddir)/src/lib-sql/libsql.la'
index daf8149e57e45916bc3f35c972dea2844820c530..63ca55a2bcd05bff05b60f568d77c5308e4770c5 100644 (file)
@@ -492,8 +492,7 @@ static const char *get_cname(X509 *cert)
        return asn1_string_to_c(str);
 }
 
-int ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io,
-                                const char *verify_name)
+int openssl_cert_match_name(SSL *ssl, const char *verify_name)
 {
        X509 *cert;
        STACK_OF(GENERAL_NAME) *gnames;
@@ -502,10 +501,7 @@ int ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io,
        bool dns_names = FALSE;
        unsigned int i, count;
 
-       if (!ssl_iostream_has_valid_client_cert(ssl_io))
-               return -1;
-
-       cert = SSL_get_peer_certificate(ssl_io->ssl);
+       cert = SSL_get_peer_certificate(ssl);
        i_assert(cert != NULL);
 
        /* verify against SubjectAltNames */
@@ -529,6 +525,15 @@ int ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io,
        return strcmp(get_cname(cert), verify_name) == 0 ? 0 : -1;
 }
 
+int ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io,
+                                const char *verify_name)
+{
+       if (!ssl_iostream_has_valid_client_cert(ssl_io))
+               return -1;
+
+       return openssl_cert_match_name(ssl_io->ssl, verify_name);
+}
+
 int ssl_iostream_handshake(struct ssl_iostream *ssl_io)
 {
        int ret;
index 0549a2d83eda92cd25345f7fb535b61f09dbd175..fecd859dc04c2e5e6a0afbe0a268d1ecaff76767 100644 (file)
@@ -60,6 +60,7 @@ void ssl_iostream_unref(struct ssl_iostream **ssl_io);
 int ssl_iostream_load_key(const struct ssl_iostream_settings *set,
                          const char *key_source, EVP_PKEY **pkey_r);
 const char *ssl_iostream_get_use_certificate_error(const char *cert);
+int openssl_cert_match_name(SSL *ssl, const char *verify_name);
 
 /* Sync plain_input/plain_output streams with BIOs. Returns TRUE if at least
    one byte was read/written. */
index 06b6eff734a79ada75774e52ad3cb5d25d569854..efe59c709800f6d24c4957400209ad14903e55e4 100644 (file)
@@ -6,6 +6,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib-auth \
        -I$(top_srcdir)/src/lib-dns \
        -I$(top_srcdir)/src/lib-master \
+       -I$(top_srcdir)/src/lib-ssl-iostream \
        -DPKG_STATEDIR=\""$(statedir)"\"
 
 liblogin_la_SOURCES = \
@@ -39,6 +40,6 @@ pkginc_lib_HEADERS = $(headers)
 
 pkglib_LTLIBRARIES = libdovecot-login.la
 libdovecot_login_la_SOURCES = 
-libdovecot_login_la_LIBADD = liblogin.la ../lib-dovecot/libdovecot.la
+libdovecot_login_la_LIBADD = liblogin.la ../lib-ssl-iostream/libssl_iostream.la ../lib-dovecot/libdovecot.la
 libdovecot_login_la_DEPENDENCIES = liblogin.la
 libdovecot_login_la_LDFLAGS = -export-dynamic
index 4b1829264433f6b9b6ed9a6b49fa626ef8b66bc4..0b42c8ba2967b6f078dd574520a4707b2e4fe91e 100644 (file)
@@ -507,18 +507,24 @@ static int login_proxy_ssl_handshaked(void *context)
 {
        struct login_proxy *proxy = context;
 
-       if ((proxy->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0 ||
-           ssl_proxy_has_valid_client_cert(proxy->ssl_server_proxy))
+       if ((proxy->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0)
                return 0;
 
-       if (!ssl_proxy_has_broken_client_cert(proxy->ssl_server_proxy)) {
+       if (ssl_proxy_has_broken_client_cert(proxy->ssl_server_proxy)) {
+               client_log_err(proxy->client, t_strdup_printf(
+                       "proxy: Received invalid SSL certificate from %s:%u",
+                       proxy->host, proxy->port));
+       } else if (!ssl_proxy_has_valid_client_cert(proxy->ssl_server_proxy)) {
                client_log_err(proxy->client, t_strdup_printf(
                        "proxy: SSL certificate not received from %s:%u",
                        proxy->host, proxy->port));
-       } else {
+       } else if (ssl_proxy_cert_match_name(proxy->ssl_server_proxy,
+                                            proxy->host) < 0) {
                client_log_err(proxy->client, t_strdup_printf(
-                       "proxy: Received invalid SSL certificate from %s:%u",
+                       "proxy: hostname doesn't match SSL certificate at %s:%u",
                        proxy->host, proxy->port));
+       } else {
+               return 0;
        }
        proxy->disconnecting = TRUE;
        return -1;
index 76ee4246d5ca1ecf5ca2bd12cf1aaa0f7a2b5d71..64a0d4503811fef64721e64a33af5aac4b576439 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifdef HAVE_OPENSSL
 
+#include "iostream-openssl.h"
 #include <openssl/crypto.h>
 #include <openssl/x509.h>
 #include <openssl/pem.h>
@@ -665,6 +666,11 @@ bool ssl_proxy_has_broken_client_cert(struct ssl_proxy *proxy)
        return proxy->cert_received && proxy->cert_broken;
 }
 
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy, const char *verify_name)
+{
+       return openssl_cert_match_name(proxy->ssl, verify_name);
+}
+
 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy)
 {
        X509 *x509;
index 8e7e3a94f9b6fec44a1f3780267280b3730ae07d..466f79ee6822a6a4d5759902bea33df069637397 100644 (file)
@@ -46,6 +46,12 @@ bool ssl_proxy_has_broken_client_cert(struct ssl_proxy *proxy ATTR_UNUSED)
        return FALSE;
 }
 
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy ATTR_UNUSED,
+                             const char *verify_name ATTR_UNUSED)
+{
+       return -1;
+}
+
 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy ATTR_UNUSED)
 {
        return NULL;
index 7be84b76b5ae977ce6457adb9f335d092bbe9e6d..0fb456bacb7784887c80b7c4fb0fb472ce9da0ba 100644 (file)
@@ -24,6 +24,7 @@ void ssl_proxy_start(struct ssl_proxy *proxy);
 void ssl_proxy_set_client(struct ssl_proxy *proxy, struct client *client);
 bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy) ATTR_PURE;
 bool ssl_proxy_has_broken_client_cert(struct ssl_proxy *proxy);
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy, const char *verify_name);
 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy);
 bool ssl_proxy_is_handshaked(const struct ssl_proxy *proxy) ATTR_PURE;
 const char *ssl_proxy_get_last_error(const struct ssl_proxy *proxy) ATTR_PURE;