[Commits] [SCM] claws branch, master, updated. 3.9.3-84-g4d0f2b9

colin at claws-mail.org colin at claws-mail.org
Wed Apr 23 11:03:29 CEST 2014


The branch master of project "claws" (Claws Mail) has been updated
       via  4d0f2b9b14819b26fbaa72ad129ec0c03e41400f (commit)
       via  dda3675203030f329d527c697e14342c9c13a75c (commit)
       via  b0c17cd08e482dbda407dabdc952dfcf5d8fdb6e (commit)
      from  4242394d7e6eaf7628486cf099b92b99efd88571 (commit)


- Log -----------------------------------------------------------------
commit 4d0f2b9b14819b26fbaa72ad129ec0c03e41400f
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 23 11:01:42 2014 +0200

    Implement certificate chain verification; fix leak; fix return code
    for etpan_certificate_check().

diff --git a/src/common/ssl_certificate.c b/src/common/ssl_certificate.c
index 72f73ac..48e55c9 100644
--- a/src/common/ssl_certificate.c
+++ b/src/common/ssl_certificate.c
@@ -207,33 +207,73 @@ size_t gnutls_i2d_PrivateKey(gnutls_x509_privkey_t pkey, unsigned char **output)
 	return key_size;
 }
 
-static gnutls_x509_crt_t gnutls_d2i_X509_fp(FILE *fp, int format)
+static int gnutls_d2i_X509_list_fp(FILE *fp, int format, gnutls_x509_crt_t **cert_list, gint *num_certs)
 {
-	gnutls_x509_crt_t cert = NULL;
+	gnutls_x509_crt_t *crt_list;
+	unsigned int max = 512;
+	unsigned int flags = 0;
 	gnutls_datum_t tmp;
 	struct stat s;
 	int r;
+
+	*cert_list = NULL;
+	*num_certs = 0;
+
+	if (fp == NULL)
+		return -ENOENT;
+
 	if (fstat(fileno(fp), &s) < 0) {
 		perror("fstat");
-		return NULL;
+		return -errno;
 	}
+
+	crt_list=(gnutls_x509_crt_t*)malloc(max*sizeof(gnutls_x509_crt_t));
 	tmp.data = malloc(s.st_size);
 	memset(tmp.data, 0, s.st_size);
 	tmp.size = s.st_size;
 	if (fread (tmp.data, 1, s.st_size, fp) < s.st_size) {
 		perror("fread");
 		free(tmp.data);
-		return NULL;
+		free(crt_list);
+		return -EIO;
 	}
 
-	gnutls_x509_crt_init(&cert);
-	if ((r = gnutls_x509_crt_import(cert, &tmp, (format == 0)?GNUTLS_X509_FMT_DER:GNUTLS_X509_FMT_PEM)) < 0) {
+	if ((r = gnutls_x509_crt_list_import(crt_list, &max, 
+			&tmp, format, flags)) < 0) {
 		debug_print("cert import failed: %s\n", gnutls_strerror(r));
-		gnutls_x509_crt_deinit(cert);
-		cert = NULL;
+		free(tmp.data);
+		free(crt_list);
+		return r;
 	}
 	free(tmp.data);
-	debug_print("got cert! %p\n", cert);
+	debug_print("got %d certs in crt_list! %p\n", max, &crt_list);
+
+	*cert_list = crt_list;
+	*num_certs = max;
+
+	return r;
+}
+
+/* return one certificate, read from file */
+static gnutls_x509_crt_t gnutls_d2i_X509_fp(FILE *fp, int format)
+{
+	gnutls_x509_crt_t *certs = NULL;
+	gnutls_x509_crt_t cert = NULL;
+	int i, ncerts, r;
+
+	if ((r = gnutls_d2i_X509_list_fp(fp, format, &certs, &ncerts)) < 0) {
+		return NULL;
+	}
+
+	if (ncerts == 0)
+		return NULL;
+
+	for (i = 1; i < ncerts; i++)
+		gnutls_x509_crt_deinit(certs[i]);
+
+	cert = certs[0];
+	free(certs);
+
 	return cert;
 }
 
@@ -474,8 +514,6 @@ static guint check_cert(gnutls_x509_crt_t cert)
 	gnutls_x509_crt_t *ca_list;
 	unsigned int max = 512;
 	unsigned int flags = 0;
-	gnutls_datum_t tmp;
-	struct stat s;
 	int r, i;
 	unsigned int status;
 	FILE *fp;
@@ -485,34 +523,12 @@ static guint check_cert(gnutls_x509_crt_t cert)
 	else
 		return (guint)-1;
 
-	if (fstat(fileno(fp), &s) < 0) {
-		perror("fstat");
-		fclose(fp);
-		return (guint)-1;
-	}
-
-	ca_list=(gnutls_x509_crt_t*)malloc(max*sizeof(gnutls_x509_crt_t));
-	tmp.data = malloc(s.st_size);
-	memset(tmp.data, 0, s.st_size);
-	tmp.size = s.st_size;
-	if (fread (tmp.data, 1, s.st_size, fp) < s.st_size) {
-		perror("fread");
-		free(tmp.data);
-		free(ca_list);
-		fclose(fp);
-		return (guint)-1;
-	}
-
-	if ((r = gnutls_x509_crt_list_import(ca_list, &max, 
-			&tmp, GNUTLS_X509_FMT_PEM, flags)) < 0) {
+	if ((r = gnutls_d2i_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &ca_list, &max)) < 0) {
 		debug_print("cert import failed: %s\n", gnutls_strerror(r));
-		free(tmp.data);
-		free(ca_list);
 		fclose(fp);
 		return (guint)-1;
 	}
-	free(tmp.data);
-	debug_print("got %d certs in ca_list! %p\n", max, &ca_list);
+
 	r = gnutls_x509_crt_verify(cert, ca_list, max, flags, &status);
 	fclose(fp);
 
@@ -649,18 +665,44 @@ gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const
 
 gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, const gchar *host, gushort port)
 {
+	int ncas = 0, ncrls = 0;
+	gnutls_x509_crt_t *cas = NULL;
+	gnutls_x509_crl_t *crls = NULL;
 	gboolean result = FALSE;
+	int i;
 	gint status;
 
+	if (claws_ssl_get_cert_file()) {
+		FILE *fp = g_fopen(claws_ssl_get_cert_file(), "rb");
+		int r = -errno;
+
+		if (fp) {
+			r = gnutls_d2i_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &cas, &ncas);
+			fclose(fp);
+		}
+
+		if (r < 0)
+			g_warning("Can't read SSL_CERT_FILE %s: %s\n",
+				claws_ssl_get_cert_file(), 
+				gnutls_strerror(r));
+	} else {
+		debug_print("Can't find SSL ca-certificates file\n");
+	}
+
+
 	gnutls_x509_crt_list_verify (certs,
                              chain_len,
-                             NULL, 0,
+                             cas, ncas,
                              NULL, 0,
                              GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
                              &status);
 
 	result = ssl_certificate_check(certs[0], status, host, port);
 
+	for (i = 0; i < ncas; i++)
+		gnutls_x509_crt_deinit(cas[i]);
+	free(cas);
+
 	return result;
 }
 
diff --git a/src/etpan/etpan-ssl.c b/src/etpan/etpan-ssl.c
index c9dc9d8..f99955b 100644
--- a/src/etpan/etpan-ssl.c
+++ b/src/etpan/etpan-ssl.c
@@ -125,6 +125,7 @@ gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port
 
 	for (i = 0; i < chain_len; i++)
 		gnutls_x509_crt_deinit(certs[i]);
+	free(certs);
 
 	return result;
 #endif
diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c
index 1073683..179f352 100644
--- a/src/etpan/imap-thread.c
+++ b/src/etpan/imap-thread.c
@@ -570,7 +570,7 @@ int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
 
 	if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
 	     result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
-		if (etpan_certificate_check(imap->imap_stream, server, port) < 0)
+		if (etpan_certificate_check(imap->imap_stream, server, port) != TRUE)
 			result.error = MAILIMAP_ERROR_SSL;
 	}
 	debug_print("connect %d with imap %p\n", result.error, imap);
@@ -1107,7 +1107,7 @@ int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
 	debug_print("imap starttls - end\n");
 
 	if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
-		if (etpan_certificate_check(param.imap->imap_stream, host, port) < 0)
+		if (etpan_certificate_check(param.imap->imap_stream, host, port) != TRUE)
 			return MAILIMAP_ERROR_SSL;
 	}	
 	return result.error;
diff --git a/src/etpan/nntp-thread.c b/src/etpan/nntp-thread.c
index 84a2f83..7708d31 100644
--- a/src/etpan/nntp-thread.c
+++ b/src/etpan/nntp-thread.c
@@ -423,7 +423,7 @@ int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	threaded_run(folder, &param, &result, connect_ssl_run);
 
 	if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) {
-		if (etpan_certificate_check(nntp->nntp_stream, server, port) < 0)
+		if (etpan_certificate_check(nntp->nntp_stream, server, port) != TRUE)
 			return -1;
 	}
 	debug_print("connect %d with nntp %p\n", result.error, nntp);

commit dda3675203030f329d527c697e14342c9c13a75c
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 23 09:42:55 2014 +0200

    Implement certificate chain retrieval and passing. CAs are not loaded
    yet.

diff --git a/src/common/ssl_certificate.c b/src/common/ssl_certificate.c
index 84e017e..72f73ac 100644
--- a/src/common/ssl_certificate.c
+++ b/src/common/ssl_certificate.c
@@ -647,6 +647,23 @@ gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const
 	return TRUE;
 }
 
+gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, const gchar *host, gushort port)
+{
+	gboolean result = FALSE;
+	gint status;
+
+	gnutls_x509_crt_list_verify (certs,
+                             chain_len,
+                             NULL, 0,
+                             NULL, 0,
+                             GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+                             &status);
+
+	result = ssl_certificate_check(certs[0], status, host, port);
+
+	return result;
+}
+
 gnutls_x509_crt_t ssl_certificate_get_x509_from_pem_file(const gchar *file)
 {
 	gnutls_x509_crt_t x509 = NULL;
diff --git a/src/common/ssl_certificate.h b/src/common/ssl_certificate.h
index 8bbe2ac..fd8822a 100644
--- a/src/common/ssl_certificate.h
+++ b/src/common/ssl_certificate.h
@@ -58,6 +58,7 @@ struct _SSLCertHookData
 
 SSLCertificate *ssl_certificate_find (const gchar *host, gushort port, const gchar *fingerprint);
 gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const gchar *host, gushort port);
+gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, const gchar *host, gushort port);
 void ssl_certificate_destroy(SSLCertificate *cert);
 void ssl_certificate_delete_from_disk(SSLCertificate *cert);
 char * readable_fingerprint(unsigned char *src, int len);
diff --git a/src/etpan/etpan-ssl.c b/src/etpan/etpan-ssl.c
index 6642e40..c9dc9d8 100644
--- a/src/etpan/etpan-ssl.c
+++ b/src/etpan/etpan-ssl.c
@@ -26,6 +26,7 @@
 #ifdef USE_GNUTLS
 #ifdef HAVE_LIBETPAN
 #include <libetpan/libetpan.h>
+#include <libetpan/libetpan_version.h>
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 #include <stdlib.h>
@@ -33,6 +34,7 @@
 #include <glib/gi18n.h>
 #include <errno.h>
 
+#include "etpan-ssl.h"
 #include "ssl_certificate.h"
 #include "utils.h"
 #include "log.h"
@@ -40,6 +42,7 @@
 
 gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port)
 {
+#if (!defined LIBETPAN_API_CURRENT || LIBETPAN_API_CURRENT < 18)
 	unsigned char *cert_der = NULL;
 	int len;
 	gnutls_x509_crt_t cert = NULL;
@@ -75,6 +78,56 @@ gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port
 		gnutls_x509_crt_deinit(cert);
 		return FALSE;
 	}
+#else
+	carray *certs_der = NULL;
+	gint chain_len = 0, i;
+	gnutls_x509_crt_t *certs = NULL;
+	gboolean result;
+
+	if (stream == NULL)
+		return FALSE;
+
+	certs_der = mailstream_get_certificate_chain(stream);
+	if (!certs_der) {
+		g_warning("could not get certs");
+		return FALSE;
+	}
+	chain_len = carray_count(certs_der);
+
+	certs = malloc(sizeof(gnutls_x509_crt_t) * chain_len);
+	if  (certs == NULL) {
+		g_warning("could not allocate certs");
+		return FALSE;
+	}
+
+	result = TRUE;
+	for (i = 0; i < chain_len; i++) {
+		MMAPString *cert_str = carray_get(certs_der, i);
+		gnutls_datum_t tmp;
+
+		tmp.data = malloc(cert_str->len);
+		memcpy(tmp.data, cert_str->str, cert_str->len);
+		tmp.size = cert_str->len;
+
+		mmap_string_free(cert_str);
+
+		gnutls_x509_crt_init(&certs[i]);
+		if (gnutls_x509_crt_import(certs[i], &tmp, GNUTLS_X509_FMT_DER) < 0)
+			result = FALSE;
+
+		free(tmp.data);
+	}
+
+	carray_free(certs_der);
+
+	if (result == TRUE)
+		result = ssl_certificate_check_chain(certs, chain_len, host, port);
+
+	for (i = 0; i < chain_len; i++)
+		gnutls_x509_crt_deinit(certs[i]);
+
+	return result;
+#endif
 }
 
 void etpan_connect_ssl_context_cb(struct mailstream_ssl_context * ssl_context, void * data)

commit b0c17cd08e482dbda407dabdc952dfcf5d8fdb6e
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 23 09:14:33 2014 +0200

    Factorize SSL things in etpan

diff --git a/src/etpan/Makefile.am b/src/etpan/Makefile.am
index b4bfe62..eb343b2 100644
--- a/src/etpan/Makefile.am
+++ b/src/etpan/Makefile.am
@@ -5,7 +5,8 @@ noinst_LTLIBRARIES = libclawsetpan.la
 libclawsetpan_la_SOURCES = \
 	etpan-thread-manager.c \
 	imap-thread.c \
-	nntp-thread.c
+	nntp-thread.c \
+	etpan-ssl.c
 
 clawsetpanincludedir = $(pkgincludedir)/etpan
 clawsetpaninclude_HEADERS = \
@@ -13,7 +14,8 @@ clawsetpaninclude_HEADERS = \
 	etpan-thread-manager.h \
 	etpan-errors.h \
 	imap-thread.h \
-	nntp-thread.h
+	nntp-thread.h \
+	etpan-ssl.h
 
 INCLUDES = \
 	-I$(top_srcdir)/src \
diff --git a/src/etpan/etpan-ssl.c b/src/etpan/etpan-ssl.c
new file mode 100644
index 0000000..6642e40
--- /dev/null
+++ b/src/etpan/etpan-ssl.c
@@ -0,0 +1,121 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2012 Colin Leroy <colin at colino.net> 
+ * and the Claws Mail team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#include "claws-features.h"
+#endif
+
+#ifdef USE_GNUTLS
+#ifdef HAVE_LIBETPAN
+#include <libetpan/libetpan.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <errno.h>
+
+#include "ssl_certificate.h"
+#include "utils.h"
+#include "log.h"
+#include "prefs_account.h"
+
+gboolean etpan_certificate_check(mailstream *stream, const char *host, gint port)
+{
+	unsigned char *cert_der = NULL;
+	int len;
+	gnutls_x509_crt_t cert = NULL;
+	gnutls_datum_t tmp;
+
+	if (stream == NULL)
+		return FALSE;
+
+	len = (int)mailstream_ssl_get_certificate(stream, &cert_der);
+
+	if (cert_der == NULL || len < 0) {
+		g_warning("no cert presented.\n");
+		return FALSE;
+	}
+
+	tmp.data = malloc(len);
+	memcpy(tmp.data, cert_der, len);
+	tmp.size = len;
+	gnutls_x509_crt_init(&cert);
+
+	free(cert_der);
+
+	if (gnutls_x509_crt_import(cert, &tmp, GNUTLS_X509_FMT_DER) < 0) {
+		free(tmp.data);
+		g_warning("IMAP: can't get cert\n");
+		return FALSE;
+	} else if (ssl_certificate_check(cert, (guint)-1, host, port) == TRUE) {
+		free(tmp.data);
+		gnutls_x509_crt_deinit(cert);
+		return TRUE;
+	} else {
+		free(tmp.data);
+		gnutls_x509_crt_deinit(cert);
+		return FALSE;
+	}
+}
+
+void etpan_connect_ssl_context_cb(struct mailstream_ssl_context * ssl_context, void * data)
+{
+	PrefsAccount *account = (PrefsAccount *)data;
+	const gchar *cert_path = NULL;
+	const gchar *password = NULL;
+	gnutls_x509_crt_t x509 = NULL;
+	gnutls_x509_privkey_t pkey = NULL;
+
+	if (account->in_ssl_client_cert_file && *account->in_ssl_client_cert_file)
+		cert_path = account->in_ssl_client_cert_file;
+	if (account->in_ssl_client_cert_pass && *account->in_ssl_client_cert_pass)
+		password = account->in_ssl_client_cert_pass;
+
+	if (mailstream_ssl_set_client_certificate_data(ssl_context, NULL, 0) < 0 ||
+	    mailstream_ssl_set_client_private_key_data(ssl_context, NULL, 0) < 0)
+		debug_print("Impossible to set the client certificate.\n");
+	x509 = ssl_certificate_get_x509_from_pem_file(cert_path);
+	pkey = ssl_certificate_get_pkey_from_pem_file(cert_path);
+	if (!(x509 && pkey)) {
+		/* try pkcs12 format */
+		ssl_certificate_get_x509_and_pkey_from_p12_file(cert_path, password, &x509, &pkey);
+	}
+	if (x509 && pkey) {
+		unsigned char *x509_der = NULL, *pkey_der = NULL;
+		size_t x509_len, pkey_len;
+
+		x509_len = (size_t)gnutls_i2d_X509(x509, &x509_der);
+		pkey_len = (size_t)gnutls_i2d_PrivateKey(pkey, &pkey_der);
+		if (x509_len > 0 && pkey_len > 0) {
+			if (mailstream_ssl_set_client_certificate_data(ssl_context, x509_der, x509_len) < 0 ||
+			    mailstream_ssl_set_client_private_key_data(ssl_context, pkey_der, pkey_len) < 0) 
+				log_error(LOG_PROTOCOL, _("Impossible to set the client certificate.\n"));
+			g_free(x509_der);
+			g_free(pkey_der);
+		}
+		gnutls_x509_crt_deinit(x509);
+		gnutls_x509_privkey_deinit(pkey);
+	}
+}
+
+#endif /* USE_GNUTLS */
+#endif /* HAVE_LIBETPAN */
diff --git a/src/etpan/etpan-ssl.h b/src/etpan/etpan-ssl.h
new file mode 100644
index 0000000..5607d1a
--- /dev/null
+++ b/src/etpan/etpan-ssl.h
@@ -0,0 +1,40 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2012 Colin Leroy <colin at colino.net> 
+ * and the Claws Mail team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifndef __ETPAN_SSL_H__
+#define __ETPAN_SSL_H__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#include "claws-features.h"
+#endif
+
+#ifdef USE_GNUTLS
+#ifdef HAVE_LIBETPAN
+
+#include <libetpan/libetpan.h>
+
+gboolean etpan_certificate_check(mailstream *imap_stream, const char *host, gint port);
+void etpan_connect_ssl_context_cb(struct mailstream_ssl_context * ssl_context, void * data);
+
+#endif /* USE_GNUTLS */
+#endif /* HAVE_LIBETPAN */
+
+#endif /* __ETPAN_SSL_H__ */
diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c
index ad5e3b3..1073683 100644
--- a/src/etpan/imap-thread.c
+++ b/src/etpan/imap-thread.c
@@ -41,6 +41,7 @@
 #include <gtk/gtk.h>
 #include <log.h>
 #include "etpan-thread-manager.h"
+#include "etpan-ssl.h"
 #include "utils.h"
 #include "mainwindow.h"
 #include "ssl.h"
@@ -506,93 +507,17 @@ int imap_threaded_connect(Folder * folder, const char * server, int port)
 	value.data = imap;
 	value.len = 0;
 	chash_set(session_hash, &key, &value, NULL);
-	
+
 	param.imap = imap;
 	param.server = server;
 	param.port = port;
-	
+
 	refresh_resolvers();
 	threaded_run(folder, &param, &result, connect_run);
-	
+
 	debug_print("connect ok %i with imap %p\n", result.error, imap);
-	
-	return result.error;
-}
 
-static int etpan_certificate_check(const unsigned char *certificate, int len, void *data)
-{
-#ifdef USE_GNUTLS
-	struct connect_param *param = (struct connect_param *)data;
-	gnutls_x509_crt_t cert = NULL;
-	gnutls_datum_t tmp;
-	
-	if (certificate == NULL || len < 0) {
-		g_warning("no cert presented.\n");
-		return 0;
-	}
-	
-	tmp.data = malloc(len);
-	memcpy(tmp.data, certificate, len);
-	tmp.size = len;
-	gnutls_x509_crt_init(&cert);
-	if (gnutls_x509_crt_import(cert, &tmp, GNUTLS_X509_FMT_DER) < 0) {
-		free(tmp.data);
-		g_warning("IMAP: can't get cert\n");
-		return 0;
-	} else if (ssl_certificate_check(cert, (guint)-1, (gchar *)param->server,
-			(gushort)param->port) == TRUE) {
-		free(tmp.data);
-		gnutls_x509_crt_deinit(cert);
-		return 0;
-	} else {
-		free(tmp.data);
-		gnutls_x509_crt_deinit(cert);
-		return -1;
-	}
-#endif
-	return 0;
-}
-
-static void connect_ssl_context_cb(struct mailstream_ssl_context * ssl_context, void * data)
-{
-#ifdef USE_GNUTLS
-	PrefsAccount *account = (PrefsAccount *)data;
-	const gchar *cert_path = NULL;
-	const gchar *password = NULL;
-	gnutls_x509_crt_t x509 = NULL;
-	gnutls_x509_privkey_t pkey = NULL;
-
-	if (account->in_ssl_client_cert_file && *account->in_ssl_client_cert_file)
-		cert_path = account->in_ssl_client_cert_file;
-	if (account->in_ssl_client_cert_pass && *account->in_ssl_client_cert_pass)
-		password = account->in_ssl_client_cert_pass;
-	
-	if (mailstream_ssl_set_client_certificate_data(ssl_context, NULL, 0) < 0 ||
-	    mailstream_ssl_set_client_private_key_data(ssl_context, NULL, 0) < 0)
-		debug_print("Impossible to set the client certificate.\n");
-	x509 = ssl_certificate_get_x509_from_pem_file(cert_path);
-	pkey = ssl_certificate_get_pkey_from_pem_file(cert_path);
-	if (!(x509 && pkey)) {
-		/* try pkcs12 format */
-		ssl_certificate_get_x509_and_pkey_from_p12_file(cert_path, password, &x509, &pkey);
-	}
-	if (x509 && pkey) {
-		unsigned char *x509_der = NULL, *pkey_der = NULL;
-		size_t x509_len, pkey_len;
-		
-		x509_len = (size_t)gnutls_i2d_X509(x509, &x509_der);
-		pkey_len = (size_t)gnutls_i2d_PrivateKey(pkey, &pkey_der);
-		if (x509_len > 0 && pkey_len > 0) {
-			if (mailstream_ssl_set_client_certificate_data(ssl_context, x509_der, x509_len) < 0 ||
-			    mailstream_ssl_set_client_private_key_data(ssl_context, pkey_der, pkey_len) < 0) 
-				log_error(LOG_PROTOCOL, _("Impossible to set the client certificate.\n"));
-			g_free(x509_der);
-			g_free(pkey_der);
-		}
-		gnutls_x509_crt_deinit(x509);
-		gnutls_x509_privkey_deinit(pkey);
-	}
-#endif
+	return result.error;
 }
 
 static void connect_ssl_run(struct etpan_thread_op * op)
@@ -608,7 +533,7 @@ static void connect_ssl_run(struct etpan_thread_op * op)
 
 	r = mailimap_ssl_connect_with_callback(param->imap,
 				 		param->server, param->port,
-						connect_ssl_context_cb, param->account);
+						etpan_connect_ssl_context_cb, param->account);
 	result->error = r;
 }
 
@@ -619,8 +544,6 @@ int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	chashdatum key;
 	chashdatum value;
 	mailimap * imap, * oldimap;
-	unsigned char *certificate = NULL;
-	int cert_len;
 	
 	oldimap = get_imap(folder);
 
@@ -647,11 +570,8 @@ int imap_threaded_connect_ssl(Folder * folder, const char * server, int port)
 
 	if ((result.error == MAILIMAP_NO_ERROR_AUTHENTICATED ||
 	     result.error == MAILIMAP_NO_ERROR_NON_AUTHENTICATED) && !etpan_skip_ssl_cert_check) {
-		cert_len = (int)mailstream_ssl_get_certificate(imap->imap_stream, &certificate);
-		if (etpan_certificate_check(certificate, cert_len, &param) < 0)
-			return -1;
-		if (certificate) 
-			free(certificate); 
+		if (etpan_certificate_check(imap->imap_stream, server, port) < 0)
+			result.error = MAILIMAP_ERROR_SSL;
 	}
 	debug_print("connect %d with imap %p\n", result.error, imap);
 	
@@ -1159,7 +1079,7 @@ static void starttls_run(struct etpan_thread_op * op)
 			return;
 		}
 
-		tls_low = mailstream_low_tls_open_with_callback(fd, connect_ssl_context_cb, param->account);
+		tls_low = mailstream_low_tls_open_with_callback(fd, etpan_connect_ssl_context_cb, param->account);
 		if (tls_low == NULL) {
 			debug_print("imap starttls run - can't tls_open\n");
 			result->error = MAILIMAP_ERROR_STREAM;
@@ -1174,8 +1094,6 @@ int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
 {
 	struct connect_param param;
 	struct starttls_result result;
-	int cert_len;
-	unsigned char *certificate = NULL;
 	
 	debug_print("imap starttls - begin\n");
 	
@@ -1189,11 +1107,8 @@ int imap_threaded_starttls(Folder * folder, const gchar *host, int port)
 	debug_print("imap starttls - end\n");
 
 	if (result.error == 0 && param.imap && !etpan_skip_ssl_cert_check) {
-		cert_len = (int)mailstream_ssl_get_certificate(param.imap->imap_stream, &certificate);
-		if (etpan_certificate_check(certificate, cert_len, &param) < 0)
-			result.error = MAILIMAP_ERROR_STREAM;
-		if (certificate) 
-			free(certificate); 
+		if (etpan_certificate_check(param.imap->imap_stream, host, port) < 0)
+			return MAILIMAP_ERROR_SSL;
 	}	
 	return result.error;
 }
diff --git a/src/etpan/nntp-thread.c b/src/etpan/nntp-thread.c
index 6d76e7a..84a2f83 100644
--- a/src/etpan/nntp-thread.c
+++ b/src/etpan/nntp-thread.c
@@ -41,6 +41,7 @@
 #include <gtk/gtk.h>
 #include <log.h>
 #include "etpan-thread-manager.h"
+#include "etpan-ssl.h"
 #include "utils.h"
 #include "mainwindow.h"
 #include "ssl_certificate.h"
@@ -373,79 +374,6 @@ int nntp_threaded_connect(Folder * folder, const char * server, int port)
 	return result.error;
 }
 
-static int etpan_certificate_check(const unsigned char *certificate, int len, void *data)
-{
-#ifdef USE_GNUTLS
-	struct connect_param *param = (struct connect_param *)data;
-	gnutls_x509_crt_t cert = NULL;
-	gnutls_datum_t tmp;
-	
-	if (certificate == NULL || len < 0) {
-		g_warning("no cert presented.\n");
-		return 0;
-	}
-	
-	tmp.data = malloc(len);
-	memcpy(tmp.data, certificate, len);
-	tmp.size = len;
-	gnutls_x509_crt_init(&cert);
-	if (gnutls_x509_crt_import(cert, &tmp, GNUTLS_X509_FMT_DER) < 0) {
-		g_warning("nntp: can't get cert\n");
-		return 0;
-	} else if (ssl_certificate_check(cert, (guint)-1,
-		(gchar *)param->server, (gushort)param->port) == TRUE) {
-		gnutls_x509_crt_deinit(cert);
-		return 0;
-	} else {
-		gnutls_x509_crt_deinit(cert);
-		return -1;
-	}
-#endif
-	return 0;
-}
-
-static void connect_ssl_context_cb(struct mailstream_ssl_context * ssl_context, void * data)
-{
-#ifdef USE_GNUTLS
-	PrefsAccount *account = (PrefsAccount *)data;
-	const gchar *cert_path = NULL;
-	const gchar *password = NULL;
-	gnutls_x509_crt_t x509 = NULL;
-	gnutls_x509_privkey_t pkey = NULL;
-
-	if (account->in_ssl_client_cert_file && *account->in_ssl_client_cert_file)
-		cert_path = account->in_ssl_client_cert_file;
-	if (account->in_ssl_client_cert_pass && *account->in_ssl_client_cert_pass)
-		password = account->in_ssl_client_cert_pass;
-	
-	if (mailstream_ssl_set_client_certificate_data(ssl_context, NULL, 0) < 0 ||
-	    mailstream_ssl_set_client_private_key_data(ssl_context, NULL, 0) < 0)
-		debug_print("Impossible to set the client certificate.\n");
-	x509 = ssl_certificate_get_x509_from_pem_file(cert_path);
-	pkey = ssl_certificate_get_pkey_from_pem_file(cert_path);
-	if (!(x509 && pkey)) {
-		/* try pkcs12 format */
-		ssl_certificate_get_x509_and_pkey_from_p12_file(cert_path, password, &x509, &pkey);
-	}
-	if (x509 && pkey) {
-		unsigned char *x509_der = NULL, *pkey_der = NULL;
-		size_t x509_len, pkey_len;
-		
-		x509_len = (size_t)gnutls_i2d_X509(x509, &x509_der);
-		pkey_len = (size_t)gnutls_i2d_PrivateKey(pkey, &pkey_der);
-		if (x509_len > 0 && pkey_len > 0) {
-			if (mailstream_ssl_set_client_certificate_data(ssl_context, x509_der, x509_len) < 0 ||
-			    mailstream_ssl_set_client_private_key_data(ssl_context, pkey_der, pkey_len) < 0) 
-				log_error(LOG_PROTOCOL, _("Impossible to set the client certificate.\n"));
-			g_free(x509_der);
-			g_free(pkey_der);
-		}
-		gnutls_x509_crt_deinit(x509);
-		gnutls_x509_privkey_deinit(pkey);
-	}
-#endif
-}
-
 static void connect_ssl_run(struct etpan_thread_op * op)
 {
 	int r;
@@ -459,7 +387,7 @@ static void connect_ssl_run(struct etpan_thread_op * op)
 
 	r = newsnntp_ssl_connect_with_callback(param->nntp,
 				 param->server, param->port,
-				 connect_ssl_context_cb, param->account);
+				 etpan_connect_ssl_context_cb, param->account);
 	result->error = r;
 }
 
@@ -470,8 +398,6 @@ int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	chashdatum key;
 	chashdatum value;
 	newsnntp * nntp, * oldnntp;
-	unsigned char *certificate = NULL;
-	int cert_len;
 	
 	oldnntp = get_nntp(folder);
 
@@ -497,11 +423,8 @@ int nntp_threaded_connect_ssl(Folder * folder, const char * server, int port)
 	threaded_run(folder, &param, &result, connect_ssl_run);
 
 	if (result.error == NEWSNNTP_NO_ERROR && !etpan_skip_ssl_cert_check) {
-		cert_len = (int)mailstream_ssl_get_certificate(nntp->nntp_stream, &certificate);
-		if (etpan_certificate_check(certificate, cert_len, &param) < 0)
+		if (etpan_certificate_check(nntp->nntp_stream, server, port) < 0)
 			return -1;
-		if (certificate) 
-			free(certificate); 
 	}
 	debug_print("connect %d with nntp %p\n", result.error, nntp);
 	

-----------------------------------------------------------------------

Summary of changes:
 src/common/ssl_certificate.c                   |  129 ++++++++++++-----
 src/common/ssl_certificate.h                   |    1 +
 src/etpan/Makefile.am                          |    6 +-
 src/etpan/etpan-ssl.c                          |  175 ++++++++++++++++++++++++
 src/{gtk/sslcertwindow.h => etpan/etpan-ssl.h} |   19 +--
 src/etpan/imap-thread.c                        |  107 ++-------------
 src/etpan/nntp-thread.c                        |   83 +----------
 7 files changed, 299 insertions(+), 221 deletions(-)
 create mode 100644 src/etpan/etpan-ssl.c
 copy src/{gtk/sslcertwindow.h => etpan/etpan-ssl.h} (71%)


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list