Implemented lm_ssl_set_ca
authorFrank Zschockelt <lm@freakysoft.de>
Mon, 04 Nov 2013 21:30:28 +0100
changeset 651 2990ee03cfa3
parent 650 a51209f570b6
child 652 c20a83e11260
Implemented lm_ssl_set_ca This enables the application to choose additional certificates to trust
loudmouth/lm-ssl-base.c
loudmouth/lm-ssl-base.h
loudmouth/lm-ssl-generic.c
loudmouth/lm-ssl-gnutls.c
loudmouth/lm-ssl-internals.h
loudmouth/lm-ssl-openssl.c
loudmouth/lm-ssl.h
loudmouth/loudmouth.sym
--- a/loudmouth/lm-ssl-base.c	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/lm-ssl-base.c	Mon Nov 04 21:30:28 2013 +0100
@@ -59,9 +59,18 @@
 }
 
 void
+_lm_ssl_base_set_ca_path (LmSSLBase   *base,
+			  const gchar *ca_path)
+{
+    if (base->ca_path)
+        g_free (base->ca_path);
+    base->ca_path = g_strdup (ca_path);
+}
+void
 _lm_ssl_base_free_fields (LmSSLBase *base)
 {
     g_free (base->expected_fingerprint);
     g_free (base->cipher_list);
+    g_free (base->ca_path);
 }
 
--- a/loudmouth/lm-ssl-base.h	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/lm-ssl-base.h	Mon Nov 04 21:30:28 2013 +0100
@@ -31,6 +31,7 @@
     gpointer        func_data;
     GDestroyNotify  data_notify;
     gchar          *cipher_list;
+    gchar          *ca_path;
     gchar          *expected_fingerprint;
     char            fingerprint[20];
     gboolean        use_starttls;
@@ -48,6 +49,9 @@
 void _lm_ssl_base_set_cipher_list (LmSSLBase   *base,
                                    const gchar *cipher_list);
 
+void _lm_ssl_base_set_ca_path (LmSSLBase   *base,
+			       const gchar *ca_path);
+
 void _lm_ssl_base_free_fields  (LmSSLBase      *base);
 
 #endif /* __LM_SSL_BASE_H__ */
--- a/loudmouth/lm-ssl-generic.c	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/lm-ssl-generic.c	Mon Nov 04 21:30:28 2013 +0100
@@ -176,6 +176,22 @@
 }
 
 /**
+ * lm_ssl_set_ca:
+ * @ssl: an #LmSSL
+ * @ca_path: path to a certificate or a directory containing certificates
+ *
+ * Sets a path to certificates which should be trusted.
+ *
+ **/
+
+void
+lm_ssl_set_ca (LmSSL *ssl, const gchar    *ca_path)
+{
+  _lm_ssl_base_set_ca_path(LM_SSL_BASE(ssl), ca_path);
+}
+
+
+/**
  * lm_ssl_use_starttls:
  * @ssl: an #LmSSL
  *
--- a/loudmouth/lm-ssl-gnutls.c	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/lm-ssl-gnutls.c	Mon Nov 04 21:30:28 2013 +0100
@@ -20,7 +20,11 @@
 
 #include <config.h>
 
+#include <errno.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <glib.h>
 
 #include "lm-debug.h"
@@ -192,6 +196,72 @@
 }
 
 gboolean
+_lm_ssl_set_ca (LmSSL       *ssl,
+                const gchar *ca_path)
+{
+    struct stat target;
+
+    if (stat (ca_path, &target) != 0) {
+        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
+               "ca_path '%s': no such file or directory", ca_path);
+        return FALSE;
+    }
+
+    if (S_ISDIR (target.st_mode)) {
+        int success = 0;
+        int worked_at_least_once = 0;
+        DIR *dir;
+        struct dirent *entry;
+
+        if ((dir = opendir (ca_path)) == NULL) {
+            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
+                   "Couldn't open '%s': %s",
+                   ca_path, strerror(errno));
+            return FALSE;
+        }
+
+        for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) {
+            struct stat file;
+            gchar *path = g_build_path ("/", ca_path, entry->d_name, NULL);
+
+            if ((stat (path, &file) == 0) && S_ISREG (file.st_mode)) {
+                success = gnutls_certificate_set_x509_trust_file (
+                                ssl->gnutls_xcred, path, GNUTLS_X509_FMT_PEM);
+                if (success > 0)
+                    worked_at_least_once = 1;
+                if (success < 0) {
+                    g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
+                           "Loading of certificate '%s' failed: %s",
+                            path, gnutls_strerror(success));
+                }
+            }
+            g_free (path);
+        }
+        closedir (dir);
+
+        if (!worked_at_least_once) {
+            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
+                   "No certificates in ca_path '%s'. Are they in PEM format?",
+                   ca_path);
+            return FALSE;
+        }
+
+    } else if (S_ISREG (target.st_mode)) {
+        int success = 0;
+        success = gnutls_certificate_set_x509_trust_file (ssl->gnutls_xcred,
+                                                          ca_path,
+                                                          GNUTLS_X509_FMT_PEM);
+        if (success < 0) {
+            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
+                   "Loading of ca_path '%s' failed: %s",
+                   ca_path, gnutls_strerror(success));
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+gboolean
 _lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error)
 {
     int ret;
@@ -205,6 +275,9 @@
     } else {
       gnutls_priority_set_direct (ssl->gnutls_session, "NORMAL", NULL);
     }
+    if (base->ca_path) {
+      _lm_ssl_set_ca(ssl, base->ca_path);
+    }
     gnutls_credentials_set (ssl->gnutls_session,
                             GNUTLS_CRD_CERTIFICATE,
                             ssl->gnutls_xcred);
--- a/loudmouth/lm-ssl-internals.h	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/lm-ssl-internals.h	Mon Nov 04 21:30:28 2013 +0100
@@ -32,6 +32,8 @@
                                            GDestroyNotify  notify);
 
 void             _lm_ssl_initialize       (LmSSL            *ssl);
+gboolean         _lm_ssl_set_ca           (LmSSL            *ssl,
+					   const gchar    *ca_path);
 gboolean         _lm_ssl_begin            (LmSSL            *ssl,
                                            gint              fd,
                                            const gchar      *server,
--- a/loudmouth/lm-ssl-openssl.c	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/lm-ssl-openssl.c	Mon Nov 04 21:30:28 2013 +0100
@@ -23,6 +23,8 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <glib.h>
 
@@ -328,6 +330,35 @@
 }
 
 gboolean
+_lm_ssl_set_ca (LmSSL       *ssl,
+		const gchar *ca_path)
+{
+    struct stat target;
+    int success = 0;
+
+    if (stat (ca_path, &target) != 0) {
+        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
+	       "ca_path '%s': no such file or directory", ca_path);
+        return FALSE;
+    }
+
+    if (S_ISDIR (target.st_mode)) {
+        success = SSL_CTX_load_verify_locations(ssl->ssl_ctx, NULL, ca_path);
+    } else if (S_ISREG (target.st_mode)) {
+        success = SSL_CTX_load_verify_locations(ssl->ssl_ctx, ca_path, NULL);
+    }
+    if (success == 0) {
+        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
+	       "Loading of ca_path '%s' failed: %s",
+	       ca_path,
+	       ERR_error_string(ERR_peek_last_error(), NULL));
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+gboolean
 _lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error)
 {
     gint ssl_ret;
@@ -345,6 +376,10 @@
     if (base->cipher_list) {
         SSL_CTX_set_cipher_list(ssl->ssl_ctx, base->cipher_list);
     }
+    if (base->ca_path) {
+        _lm_ssl_set_ca (ssl, base->ca_path);
+    }
+
     ssl->ssl = SSL_new(ssl->ssl_ctx);
     if (ssl->ssl == NULL) {
         g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "SSL_new() == NULL");
--- a/loudmouth/lm-ssl.h	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/lm-ssl.h	Mon Nov 04 21:30:28 2013 +0100
@@ -126,6 +126,9 @@
 void                  lm_ssl_set_cipher_list (LmSSL          *ssl,
                                               const gchar    *cipher_list);
 
+void                  lm_ssl_set_ca          (LmSSL *ssl,
+					      const gchar    *ca_path);
+
 const gchar *         lm_ssl_get_fingerprint (LmSSL          *ssl);
 
 void                  lm_ssl_use_starttls    (LmSSL *ssl,
--- a/loudmouth/loudmouth.sym	Fri Oct 25 00:02:50 2013 +0200
+++ b/loudmouth/loudmouth.sym	Mon Nov 04 21:30:28 2013 +0100
@@ -90,6 +90,7 @@
 lm_ssl_new
 lm_ssl_ref
 lm_ssl_unref
+lm_ssl_set_ca
 lm_ssl_set_cipher_list
 lm_ssl_use_starttls
 lm_utils_get_localtime