]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
*-login: ssl_ca_file setting changed to ssl_ca.
authorTimo Sirainen <tss@iki.fi>
Tue, 8 Dec 2009 20:06:45 +0000 (15:06 -0500)
committerTimo Sirainen <tss@iki.fi>
Tue, 8 Dec 2009 20:06:45 +0000 (15:06 -0500)
--HG--
branch : HEAD

doc/example-config/conf.d/ssl.conf
src/login-common/login-settings.c
src/login-common/login-settings.h
src/login-common/ssl-proxy-openssl.c

index 6ff88d3d2f91ca0db241cbaa5886eac2fef42785..3d79d8940e9253531fdd72ebbc446b038c64d04e 100644 (file)
@@ -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.
index 25c0bf2b3394bdfad0380563319e38a4dd94d766..527a2f67a0d402706aa02570756f71c77db6b29c 100644 (file)
@@ -23,7 +23,7 @@ static const struct setting_define login_setting_defines[] = {
        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_default_settings = {
        .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 ATTR_UNUSED, const char **error_r)
                *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";
+       if (set->ssl_verify_client_cert && *set->ssl_ca == '\0') {
+               *error_r = "ssl_verify_client_cert set, but ssl_ca 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
        return TRUE;
 #endif
 }
index c13ec0163b9bd9f29e9b3b4e5c13c865308f89a3..2d57b8e2fb2c39f92a634e2063900ddd55478ae5 100644 (file)
@@ -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;
index 5268ce66652fca44a5fbe4c93430b3bfbfdd717a..2e91f31d40ea452a68f7d48e59a06e50eb7c77bb 100644 (file)
@@ -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 login_settings *set)
        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
-ssl_proxy_ctx_init(SSL_CTX *ssl_ctx, const struct login_settings *set)
+static STACK_OF(X509_NAME) *load_ca(X509_STORE *store, const char *ca)
 {
-       SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
+       /* 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;
 
-       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());
+       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 != '\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_ctx, const char *ca_file)
 #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 login_settings *set)
        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 login_settings *set)
        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(struct ssl_server_context **_ctx)
 
 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)