Implement certificate chain retrieval and passing. CAs are not loaded
authorColin Leroy <colin@colino.net>
Wed, 23 Apr 2014 07:42:55 +0000 (09:42 +0200)
committerColin Leroy <colin@colino.net>
Wed, 23 Apr 2014 07:42:55 +0000 (09:42 +0200)
yet.

src/common/ssl_certificate.c
src/common/ssl_certificate.h
src/etpan/etpan-ssl.c

index 84e017e..72f73ac 100644 (file)
@@ -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;
index 8bbe2ac..fd8822a 100644 (file)
@@ -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);
index 6642e40..c9dc9d8 100644 (file)
@@ -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)