dovecot-2.0: *-login: ssl_ca_file setting changed to ssl_ca.

dovecot at dovecot.org dovecot at dovecot.org
Tue Dec 8 22:08:47 EET 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/0da209ff80d5
changeset: 10428:0da209ff80d5
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Dec 08 15:06:45 2009 -0500
description:
*-login: ssl_ca_file setting changed to ssl_ca.

diffstat:

4 files changed, 71 insertions(+), 36 deletions(-)
doc/example-config/conf.d/ssl.conf   |    8 +--
src/login-common/login-settings.c    |   20 ++------
src/login-common/login-settings.h    |    2 
src/login-common/ssl-proxy-openssl.c |   77 ++++++++++++++++++++++++++--------

diffs (228 lines):

diff -r 3a1f6c1a8485 -r 0da209ff80d5 doc/example-config/conf.d/ssl.conf
--- a/doc/example-config/conf.d/ssl.conf	Tue Dec 08 13:51:49 2009 -0500
+++ b/doc/example-config/conf.d/ssl.conf	Tue Dec 08 15:06:45 2009 -0500
@@ -18,10 +18,10 @@ ssl_key = </etc/ssl/private/dovecot.pem
 # root owned 0600 file by using !include_try <path>.
 #ssl_key_password =
 
-# File containing trusted SSL certificate authorities. Set this only if you
-# intend to use ssl_verify_client_cert=yes. The CAfile should contain the
-# CA-certificate(s) followed by the matching CRL(s).
-#ssl_ca_file = 
+# PEM encoded trusted certificate authority. Set this only if you intend to use
+# ssl_verify_client_cert=yes. The file should contain the CA certificate(s)
+# followed by the matching CRL(s). (e.g. ssl_ca = </etc/ssl/certs/ca.pem)
+#ssl_ca = 
 
 # Request client to send a certificate. If you also want to require it, set
 # auth_ssl_require_client_cert=yes in auth section.
diff -r 3a1f6c1a8485 -r 0da209ff80d5 src/login-common/login-settings.c
--- a/src/login-common/login-settings.c	Tue Dec 08 13:51:49 2009 -0500
+++ b/src/login-common/login-settings.c	Tue Dec 08 15:06:45 2009 -0500
@@ -23,7 +23,7 @@ static const struct setting_define login
 	DEF(SET_STR, login_log_format),
 
 	DEF(SET_ENUM, ssl),
-	DEF(SET_STR, ssl_ca_file),
+	DEF(SET_STR, ssl_ca),
 	DEF(SET_STR, ssl_cert),
 	DEF(SET_STR, ssl_key),
 	DEF(SET_STR, ssl_key_password),
@@ -52,7 +52,7 @@ static const struct login_settings login
 	.login_log_format = "%$: %s",
 
 	.ssl = "yes:no:required",
-	.ssl_ca_file = "",
+	.ssl_ca = "",
 	.ssl_cert = "",
 	.ssl_key = "",
 	.ssl_key_password = "",
@@ -110,18 +110,10 @@ static int ssl_settings_check(void *_set
 		*error_r = "ssl enabled, but ssl_key not set";
 		return FALSE;
 	}
-	if (set->ssl_verify_client_cert && *set->ssl_ca_file == '\0') {
-		*error_r = "ssl_verify_client_cert set, but ssl_ca_file not";
-		return FALSE;
-	}
-
-#ifndef CONFIG_BINARY
-	if (*set->ssl_ca_file != '\0' && access(set->ssl_ca_file, R_OK) < 0) {
-		*error_r = t_strdup_printf("ssl_ca_file: access(%s) failed: %m",
-					   set->ssl_ca_file);
-		return FALSE;
-	}
-#endif
+	if (set->ssl_verify_client_cert && *set->ssl_ca == '\0') {
+		*error_r = "ssl_verify_client_cert set, but ssl_ca not";
+		return FALSE;
+	}
 	return TRUE;
 #endif
 }
diff -r 3a1f6c1a8485 -r 0da209ff80d5 src/login-common/login-settings.h
--- a/src/login-common/login-settings.h	Tue Dec 08 13:51:49 2009 -0500
+++ b/src/login-common/login-settings.h	Tue Dec 08 15:06:45 2009 -0500
@@ -9,7 +9,7 @@ struct login_settings {
 	const char *login_log_format_elements, *login_log_format;
 
 	const char *ssl;
-	const char *ssl_ca_file;
+	const char *ssl_ca;
 	const char *ssl_cert;
 	const char *ssl_key;
 	const char *ssl_key_password;
diff -r 3a1f6c1a8485 -r 0da209ff80d5 src/login-common/ssl-proxy-openssl.c
--- a/src/login-common/ssl-proxy-openssl.c	Tue Dec 08 13:51:49 2009 -0500
+++ b/src/login-common/ssl-proxy-openssl.c	Tue Dec 08 15:06:45 2009 -0500
@@ -82,7 +82,7 @@ struct ssl_server_context {
 
 	const char *cert;
 	const char *key;
-	const char *ca_file;
+	const char *ca;
 	const char *cipher_list;
 	bool verify_client_cert;
 };
@@ -598,7 +598,7 @@ ssl_server_context_get(const struct logi
 	memset(&lookup_ctx, 0, sizeof(lookup_ctx));
 	lookup_ctx.cert = set->ssl_cert;
 	lookup_ctx.key = set->ssl_key;
-	lookup_ctx.ca_file = set->ssl_ca_file;
+	lookup_ctx.ca = set->ssl_ca;
 	lookup_ctx.cipher_list = set->ssl_cipher_list;
 	lookup_ctx.verify_client_cert = set->ssl_verify_client_cert;
 
@@ -869,26 +869,65 @@ static bool is_pem_key(const char *cert)
 	return strstr(cert, "PRIVATE KEY---") != NULL;
 }
 
-static void
+static STACK_OF(X509_NAME) *load_ca(X509_STORE *store, const char *ca)
+{
+	/* mostly just copy&pasted from X509_load_cert_crl_file() */
+	STACK_OF(X509_INFO) *inf;
+	STACK_OF(X509_NAME) *xnames;
+	X509_INFO *itmp;
+	X509_NAME *xname;
+	BIO *bio;
+	int i;
+
+	bio = BIO_new_mem_buf(t_strdup_noconst(ca), strlen(ca));
+	if (bio == NULL)
+		i_fatal("BIO_new_mem_buf() failed");
+	inf = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+	if (inf == NULL)
+		i_fatal("Couldn't parse ssl_ca: %s", ssl_last_error());
+	BIO_free(bio);
+
+	xnames = sk_X509_NAME_new_null();
+	if (xnames == NULL)
+		i_fatal("sk_X509_NAME_new_null() failed");
+	for(i = 0; i < sk_X509_INFO_num(inf); i++) {
+		itmp = sk_X509_INFO_value(inf, i);
+		if(itmp->x509) {
+			X509_STORE_add_cert(store, itmp->x509);
+			xname = X509_get_subject_name(itmp->x509);
+			if (xname != NULL)
+				xname = X509_NAME_dup(xname);
+			if (xname != NULL)
+				sk_X509_NAME_push(xnames, xname);
+		}
+		if(itmp->crl)
+			X509_STORE_add_crl(store, itmp->crl);
+	}
+	sk_X509_INFO_pop_free(inf, X509_INFO_free);
+	return xnames;
+}
+
+static STACK_OF(X509_NAME) *
 ssl_proxy_ctx_init(SSL_CTX *ssl_ctx, const struct login_settings *set)
 {
+	X509_STORE *store;
+	STACK_OF(X509_NAME) *xnames = NULL;
+
 	SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
-
-	if (*set->ssl_ca_file != '\0') {
-		if (SSL_CTX_load_verify_locations(ssl_ctx, set->ssl_ca_file,
-						  NULL) != 1) {
-			i_fatal("Can't load CA file %s: %s",
-				set->ssl_ca_file, ssl_last_error());
-		}
+	if (*set->ssl_ca != '\0') {
+		/* set trusted CA certs */
+		store = SSL_CTX_get_cert_store(ssl_ctx);
+		xnames = load_ca(store, set->ssl_ca);
 	}
 	SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback);
 	if (SSL_CTX_need_tmp_RSA(ssl_ctx))
 		SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
 	SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
+	return xnames;
 }
 
 static void
-ssl_proxy_ctx_verify_client(SSL_CTX *ssl_ctx, const char *ca_file)
+ssl_proxy_ctx_verify_client(SSL_CTX *ssl_ctx, STACK_OF(X509_NAME) *ca_names)
 {
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
 	X509_STORE *store;
@@ -899,7 +938,8 @@ ssl_proxy_ctx_verify_client(SSL_CTX *ssl
 #endif
 	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
 			   ssl_verify_client_cert);
-	SSL_CTX_set_client_CA_list(ssl_ctx, SSL_load_client_CA_file(ca_file));
+	/* set list of CA names that are sent to client */
+	SSL_CTX_set_client_CA_list(ssl_ctx, ca_names);
 }
 
 static const char *ssl_proxy_get_use_certificate_error(const char *cert)
@@ -1043,20 +1083,21 @@ ssl_server_context_init(const struct log
 	struct ssl_server_context *ctx;
 	SSL_CTX *ssl_ctx;
 	pool_t pool;
+	STACK_OF(X509_NAME) *xnames;
 
 	pool = pool_alloconly_create("ssl server context", 2048);
 	ctx = i_new(struct ssl_server_context, 1);
 	ctx->pool = pool;
 	ctx->cert = p_strdup(pool, set->ssl_cert);
 	ctx->key = p_strdup(pool, set->ssl_key);
-	ctx->ca_file = p_strdup(pool, set->ssl_ca_file);
+	ctx->ca = p_strdup(pool, set->ssl_ca);
 	ctx->cipher_list = p_strdup(pool, set->ssl_cipher_list);
 	ctx->verify_client_cert = set->ssl_verify_client_cert;
 
 	ctx->ctx = ssl_ctx = SSL_CTX_new(SSLv23_server_method());
 	if (ssl_ctx == NULL)
 		i_fatal("SSL_CTX_new() failed");
-	ssl_proxy_ctx_init(ssl_ctx, set);
+	xnames = ssl_proxy_ctx_init(ssl_ctx, set);
 
 	if (SSL_CTX_set_cipher_list(ssl_ctx, ctx->cipher_list) != 1) {
 		i_fatal("Can't set cipher list to '%s': %s",
@@ -1080,7 +1121,7 @@ ssl_server_context_init(const struct log
 	SSL_CTX_set_info_callback(ctx->ctx, ssl_info_callback);
 
 	if (ctx->verify_client_cert)
-		ssl_proxy_ctx_verify_client(ctx->ctx, ctx->ca_file);
+		ssl_proxy_ctx_verify_client(ctx->ctx, xnames);
 
 	hash_table_insert(ssl_servers, ctx, ctx);
 	return ctx;
@@ -1096,10 +1137,12 @@ static void ssl_server_context_deinit(st
 
 static void ssl_proxy_init_client(const struct login_settings *set)
 {
+	STACK_OF(X509_NAME) *xnames;
+
 	if ((ssl_client_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
 		i_fatal("SSL_CTX_new() failed");
-	ssl_proxy_ctx_init(ssl_client_ctx, set);
-	ssl_proxy_ctx_verify_client(ssl_client_ctx, set->ssl_ca_file);
+	xnames = ssl_proxy_ctx_init(ssl_client_ctx, set);
+	ssl_proxy_ctx_verify_client(ssl_client_ctx, xnames);
 }
 
 void ssl_proxy_init(void)


More information about the dovecot-cvs mailing list