From dda3675203030f329d527c697e14342c9c13a75c Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Wed, 23 Apr 2014 09:42:55 +0200 Subject: [PATCH] Implement certificate chain retrieval and passing. CAs are not loaded yet. --- src/common/ssl_certificate.c | 17 ++++++++++++ src/common/ssl_certificate.h | 1 + src/etpan/etpan-ssl.c | 53 ++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/common/ssl_certificate.c b/src/common/ssl_certificate.c index 84e017e8b..72f73acb1 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 8bbe2ac1a..fd8822ad7 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 6642e4061..c9dc9d808 100644 --- a/src/etpan/etpan-ssl.c +++ b/src/etpan/etpan-ssl.c @@ -26,6 +26,7 @@ #ifdef USE_GNUTLS #ifdef HAVE_LIBETPAN #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include +#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) -- 2.25.1