2006-04-05 Mikael Hallendal <micke@imendio.com>
* configure.in: Define HAVE_SSL which will be set if GnuTLS or OpenSSL
is supported.
* loudmouth/Makefile.am:
* loudmouth/lm-connection.c:
* loudmouth/lm-internals.h:
* loudmouth/lm-ssl-base.[ch]:
* loudmouth/lm-ssl-generic.c:
* loudmouth/lm-ssl-gnutls.c:
* loudmouth/lm-ssl-internals.h: Took out the SSL functions from
lm-internals.h
* loudmouth/lm-ssl.[ch]:
- Refactored the SSL stuff to make room for an OpenSSL implementation.
- lm-ssl-generic and lm-ssl-base contains the shared parts between the
GnuTLS and the OpenSSL implementations. lm-ssl-gnutls.c will contain
GnuTLS specifics and lm-ssl-openssl.c will contain OpenSSL.
--- a/ChangeLog Wed Apr 05 13:19:47 2006 +0000
+++ b/ChangeLog Wed Apr 05 15:19:13 2006 +0000
@@ -1,3 +1,21 @@
+2006-04-05 Mikael Hallendal <micke@imendio.com>
+
+ * configure.in: Define HAVE_SSL which will be set if GnuTLS or OpenSSL
+ is supported.
+ * loudmouth/Makefile.am:
+ * loudmouth/lm-connection.c:
+ * loudmouth/lm-internals.h:
+ * loudmouth/lm-ssl-base.[ch]:
+ * loudmouth/lm-ssl-generic.c:
+ * loudmouth/lm-ssl-gnutls.c:
+ * loudmouth/lm-ssl-internals.h: Took out the SSL functions from
+ lm-internals.h
+ * loudmouth/lm-ssl.[ch]:
+ - Refactored the SSL stuff to make room for an OpenSSL implementation.
+ - lm-ssl-generic and lm-ssl-base contains the shared parts between the
+ GnuTLS and the OpenSSL implementations. lm-ssl-gnutls.c will contain
+ GnuTLS specifics and lm-ssl-openssl.c will contain OpenSSL.
+
2006-04-05 Mikael Hallendal <micke@imendio.com>
* Speed release of 1.0.3
--- a/configure.in Wed Apr 05 13:19:47 2006 +0000
+++ b/configure.in Wed Apr 05 15:19:13 2006 +0000
@@ -123,6 +123,10 @@
echo "Disabling SSL support"
fi
+if test x$enable_ssl = xyes; then
+ AC_DEFINE(HAVE_SSL, 1, [whether to use SSL support.])
+fi
+
dnl +-------------+
dnl | Build Flags |--------------------------------------------
dnl +-------------+
--- a/loudmouth/Makefile.am Wed Apr 05 13:19:47 2006 +0000
+++ b/loudmouth/Makefile.am Wed Apr 05 15:19:13 2006 +0000
@@ -23,7 +23,11 @@
lm-internals.h \
lm-sha.c \
lm-sha.h \
- lm-ssl.c \
+ lm-ssl-generic.c \
+ lm-ssl-gnutls.c \
+ lm-ssl-base.c \
+ lm-ssl-base.h \
+ lm-ssl-internals.h \
lm-utils.c \
lm-proxy.c \
$(NULL)
--- a/loudmouth/lm-connection.c Wed Apr 05 13:19:47 2006 +0000
+++ b/loudmouth/lm-connection.c Wed Apr 05 15:19:13 2006 +0000
@@ -37,6 +37,7 @@
#include "lm-debug.h"
#include "lm-error.h"
#include "lm-internals.h"
+#include "lm-ssl-internals.h"
#include "lm-parser.h"
#include "lm-sha.h"
#include "lm-connection.h"
--- a/loudmouth/lm-internals.h Wed Apr 05 13:19:47 2006 +0000
+++ b/loudmouth/lm-internals.h Wed Apr 05 15:19:13 2006 +0000
@@ -66,20 +66,6 @@
gboolean _lm_proxy_connect_cb (GIOChannel *source,
GIOCondition condition,
gpointer data);
-void _lm_ssl_initialize (LmSSL *ssl);
-gboolean _lm_ssl_begin (LmSSL *ssl,
- gint fd,
- const gchar *server,
- GError **error);
-GIOStatus _lm_ssl_read (LmSSL *ssl,
- gchar *buf,
- gint len,
- gsize *bytes_read);
-gint _lm_ssl_send (LmSSL *ssl,
- const gchar *str,
- gint len);
-void _lm_ssl_close (LmSSL *ssl);
-
LmHandlerResult
_lm_message_handler_handle_message (LmMessageHandler *handler,
LmConnection *connection,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/lm-ssl-base.c Wed Apr 05 15:19:13 2006 +0000
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2006 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "lm-ssl-base.h"
+#include "lm-ssl-internals.h"
+
+void
+_lm_ssl_base_init (LmSSLBase *base,
+ const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ base->ref_count = 1;
+ base->func = ssl_function;
+ base->func_data = user_data;
+ base->data_notify = notify;
+ base->fingerprint[0] = '\0';
+
+ if (expected_fingerprint) {
+ base->expected_fingerprint = g_strdup (expected_fingerprint);
+ } else {
+ base->expected_fingerprint = NULL;
+ }
+
+ if (!base->func) {
+ /* If user didn't provide an SSL func the default will be used
+ * this function will always tell the connection to continue.
+ */
+ base->func = _lm_ssl_func_always_continue;
+ }
+}
+
+void
+_lm_ssl_base_free_fields (LmSSLBase *base)
+{
+ g_free (base->expected_fingerprint);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/lm-ssl-base.h Wed Apr 05 15:19:13 2006 +0000
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2006 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LM_SSL_BASE_H__
+#define __LM_SSL_BASE_H__
+
+#include "lm-ssl.h"
+
+#define LM_SSL_BASE(x) ((LmSSLBase *) x)
+
+typedef struct _LmSSLBase LmSSLBase;
+struct _LmSSLBase {
+ LmSSLFunction func;
+ gpointer func_data;
+ GDestroyNotify data_notify;
+ gchar *expected_fingerprint;
+ char fingerprint[20];
+
+ gint ref_count;
+};
+
+void _lm_ssl_base_init (LmSSLBase *base,
+ const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+void _lm_ssl_base_free_fields (LmSSLBase *base);
+
+#endif /* __LM_SSL_BASE_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/lm-ssl-generic.c Wed Apr 05 15:19:13 2006 +0000
@@ -0,0 +1,199 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2006 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "lm-ssl.h"
+#include "lm-ssl-base.h"
+#include "lm-ssl-internals.h"
+
+LmSSLResponse
+_lm_ssl_func_always_continue (LmSSL *ssl,
+ LmSSLStatus status,
+ gpointer user_data)
+{
+ return LM_SSL_RESPONSE_CONTINUE;;
+}
+
+/* Define the SSL functions as noops if we compile without support */
+#ifndef HAVE_SSL
+
+LmSSL *
+_lm_ssl_new (const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ return NULL;
+}
+
+void
+_lm_ssl_initialize (LmSSL *ssl)
+{
+ /* NOOP */
+}
+
+gboolean
+_lm_ssl_begin (LmSSL *ssl,
+ gint fd,
+ const gchar *server,
+ GError **error)
+{
+ return TRUE;
+}
+
+GIOStatus
+_lm_ssl_read (LmSSL *ssl,
+ gchar *buf,
+ gint len,
+ gsize *bytes_read)
+{
+ /* NOOP */
+ *bytes_read = 0;
+
+ return G_IO_STATUS_EOF;
+}
+
+gboolean
+_lm_ssl_send (LmSSL *ssl, const gchar *str, gint len)
+{
+ /* NOOP */
+ return TRUE;
+}
+void
+_lm_ssl_close (LmSSL *ssl)
+{
+ /* NOOP */
+}
+
+void
+_lm_ssl_free (LmSSL *ssl)
+{
+ /* NOOP */
+}
+
+#endif /* HAVE_SSL */
+
+
+
+/**
+ * lm_ssl_new:
+ * @expected_fingerprint: The expected fingerprint. @ssl_function will be called if there is a mismatch. %NULL if you are not interested in this check.
+ * @ssl_function: Callback called to inform the user of a problem during setting up the SSL connection and how to proceed. If %NULL is passed the default function that always continues will be used.
+ * @user_data: Data sent with the callback.
+ * @notify: Function to free @user_dataa when the connection is finished. %NULL if @user_data should not be freed.
+ *
+ * Creates a new SSL struct, call #lm_connection_set_ssl to use it.
+ *
+ * Return value: A new #LmSSL struct.
+ **/
+LmSSL *
+lm_ssl_new (const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ /* The implementation of this function will be different depending
+ * on which implementation is used
+ */
+ return _lm_ssl_new (expected_fingerprint,
+ ssl_function, user_data, notify);
+}
+
+/**
+ * lm_ssl_is_supported:
+ *
+ * Checks whether Loudmouth supports SSL or not.
+ *
+ * Return value: #TRUE if this installation of Loudmouth supports SSL, otherwise returns #FALSE.
+ **/
+gboolean
+lm_ssl_is_supported (void)
+{
+#ifdef HAVE_SSL
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+
+/**
+ * lm_ssl_get_fingerprint:
+ * @ssl: an #LmSSL
+ *
+ * Returns the MD5 fingerprint of the remote server's certificate.
+ *
+ * Return value: A 16-byte array representing the fingerprint or %NULL if unknown.
+ **/
+const gchar *
+lm_ssl_get_fingerprint (LmSSL *ssl)
+{
+ g_return_val_if_fail (ssl != NULL, NULL);
+
+ return LM_SSL_BASE(ssl)->fingerprint;
+}
+
+/**
+ * lm_ssl_ref:
+ * @ssl: an #LmSSL
+ *
+ * Adds a reference to @ssl.
+ *
+ * Return value: the ssl
+ **/
+LmSSL *
+lm_ssl_ref (LmSSL *ssl)
+{
+ g_return_val_if_fail (ssl != NULL, NULL);
+
+ LM_SSL_BASE(ssl)->ref_count++;
+
+ return ssl;
+}
+
+/**
+ * lm_ssl_unref
+ * @ssl: an #LmSSL
+ *
+ * Removes a reference from @ssl. When no more references are present
+ * @ssl is freed.
+ **/
+void
+lm_ssl_unref (LmSSL *ssl)
+{
+ LmSSLBase *base;
+
+ g_return_if_fail (ssl != NULL);
+
+ base = LM_SSL_BASE (ssl);
+
+ base->ref_count --;
+
+ if (base->ref_count == 0) {
+ if (base->data_notify) {
+ (* base->data_notify) (base->func_data);
+ }
+
+ _lm_ssl_free (ssl);
+ }
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/lm-ssl-gnutls.c Wed Apr 05 15:19:13 2006 +0000
@@ -0,0 +1,274 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2006 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <glib.h>
+
+#include "lm-error.h"
+#include "lm-ssl-base.h"
+#include "lm-ssl-internals.h"
+
+#ifdef HAVE_GNUTLS
+
+#include <gnutls/x509.h>
+
+struct _LmSSL {
+ LmSSLBase base;
+
+ gnutls_session gnutls_session;
+ gnutls_certificate_client_credentials gnutls_xcred;
+};
+
+static gboolean ssl_verify_certificate (LmSSL *ssl,
+ const gchar *server);
+
+static gboolean
+ssl_verify_certificate (LmSSL *ssl, const gchar *server)
+{
+ LmSSLBase *base;
+ int status;
+
+ base = LM_SSL_BASE (ssl);
+
+ /* This verification function uses the trusted CAs in the credentials
+ * structure. So you must have installed one or more CA certificates.
+ */
+ status = gnutls_certificate_verify_peers (ssl->gnutls_session);
+
+ if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) {
+ if (base->func (ssl,
+ LM_SSL_STATUS_NO_CERT_FOUND,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ if (status & GNUTLS_CERT_INVALID
+ || status & GNUTLS_CERT_REVOKED) {
+ if (base->func (ssl, LM_SSL_STATUS_UNTRUSTED_CERT,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ if (gnutls_certificate_expiration_time_peers (ssl->gnutls_session) < time (0)) {
+ if (base->func (ssl, LM_SSL_STATUS_CERT_EXPIRED,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ if (gnutls_certificate_activation_time_peers (ssl->gnutls_session) > time (0)) {
+ if (base->func (ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ if (gnutls_certificate_type_get (ssl->gnutls_session) == GNUTLS_CRT_X509) {
+ const gnutls_datum* cert_list;
+ guint cert_list_size;
+ size_t digest_size;
+ gnutls_x509_crt cert;
+
+ cert_list = gnutls_certificate_get_peers (ssl->gnutls_session, &cert_list_size);
+ if (cert_list == NULL) {
+ if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ gnutls_x509_crt_init (&cert);
+
+ if (!gnutls_x509_crt_import (cert, &cert_list[0],
+ GNUTLS_X509_FMT_DER)) {
+ if (base->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ if (!gnutls_x509_crt_check_hostname (cert, server)) {
+ if (base->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ gnutls_x509_crt_deinit (cert);
+
+ if (gnutls_fingerprint (GNUTLS_DIG_MD5, &cert_list[0],
+ base->fingerprint,
+ &digest_size) >= 0) {
+ if (base->expected_fingerprint &&
+ memcmp (base->expected_fingerprint,
+ base->fingerprint,
+ digest_size) &&
+ base->func (ssl,
+ LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+ else if (base->func (ssl, LM_SSL_STATUS_GENERIC_ERROR,
+ base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* From lm-ssl-protected.h */
+
+LmSSL *
+_lm_ssl_new (const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ LmSSL *ssl;
+
+ ssl = g_new0 (LmSSL, 1);
+
+ _lm_ssl_base_init ((LmSSLBase *) ssl,
+ expected_fingerprint,
+ ssl_function, user_data, notify);
+
+ return ssl;
+}
+
+void
+_lm_ssl_initialize (LmSSL *ssl)
+{
+ gnutls_global_init ();
+ gnutls_certificate_allocate_credentials (&ssl->gnutls_xcred);
+}
+
+gboolean
+_lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error)
+{
+ int ret;
+ gboolean auth_ok = TRUE;
+ const int cert_type_priority[2] =
+ { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP };
+
+ gnutls_init (&ssl->gnutls_session, GNUTLS_CLIENT);
+ gnutls_set_default_priority (ssl->gnutls_session);
+ gnutls_certificate_type_set_priority (ssl->gnutls_session,
+ cert_type_priority);
+ gnutls_credentials_set (ssl->gnutls_session,
+ GNUTLS_CRD_CERTIFICATE,
+ ssl->gnutls_xcred);
+
+ gnutls_transport_set_ptr (ssl->gnutls_session,
+ (gnutls_transport_ptr) fd);
+
+ ret = gnutls_handshake (ssl->gnutls_session);
+
+ if (ret >= 0) {
+ auth_ok = ssl_verify_certificate (ssl, server);
+ }
+
+ if (ret < 0 || !auth_ok) {
+ char *errmsg;
+
+ gnutls_perror (ret);
+
+ if (!auth_ok) {
+ errmsg = "*** GNUTLS authentication error";
+ } else {
+ errmsg = "*** GNUTLS handshake failed";
+ }
+
+ g_set_error (error,
+ LM_ERROR, LM_ERROR_CONNECTION_OPEN,
+ errmsg);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GIOStatus
+_lm_ssl_read (LmSSL *ssl, gchar *buf, gint len, gsize *bytes_read)
+{
+ GIOStatus status;
+ gint b_read;
+
+ *bytes_read = 0;
+ b_read = gnutls_record_recv (ssl->gnutls_session, buf, len);
+
+ if (b_read == GNUTLS_E_AGAIN) {
+ status = G_IO_STATUS_AGAIN;
+ }
+ else if (b_read > len) {
+ status = G_IO_STATUS_EOF;
+ }
+ else if (b_read < 0) {
+ status = G_IO_STATUS_ERROR;
+ } else {
+ *bytes_read = (guint) b_read;
+ status = G_IO_STATUS_NORMAL;
+ }
+
+ return status;
+}
+
+gint
+_lm_ssl_send (LmSSL *ssl, const gchar *str, gint len)
+{
+ gint bytes_written;
+
+ bytes_written = gnutls_record_send (ssl->gnutls_session, str, len);
+
+ while (bytes_written < 0) {
+ if (bytes_written != GNUTLS_E_INTERRUPTED &&
+ bytes_written != GNUTLS_E_AGAIN) {
+ return -1;
+ }
+
+ bytes_written = gnutls_record_send (ssl->gnutls_session,
+ str, len);
+ }
+
+ return bytes_written;
+}
+
+void
+_lm_ssl_close (LmSSL *ssl)
+{
+ gnutls_deinit (ssl->gnutls_session);
+ gnutls_certificate_free_credentials (ssl->gnutls_xcred);
+ gnutls_global_deinit ();
+}
+
+void
+_lm_ssl_free (LmSSL *ssl)
+{
+ _lm_ssl_base_free_fields (LM_SSL_BASE (ssl));
+ g_free (ssl);
+}
+
+#endif /* HAVE_GNUTLS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/lm-ssl-internals.h Wed Apr 05 15:19:13 2006 +0000
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2006 Imendio AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LM_SSL_INTERNALS_H__
+#define __LM_SSL_INTERNALS_H__
+
+#include <glib.h>
+
+LmSSLResponse _lm_ssl_func_always_continue (LmSSL *ssl,
+ LmSSLStatus status,
+ gpointer user_data);
+LmSSL * _lm_ssl_new (const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+void _lm_ssl_initialize (LmSSL *ssl);
+gboolean _lm_ssl_begin (LmSSL *ssl,
+ gint fd,
+ const gchar *server,
+ GError **error);
+GIOStatus _lm_ssl_read (LmSSL *ssl,
+ gchar *buf,
+ gint len,
+ gsize *bytes_read);
+gint _lm_ssl_send (LmSSL *ssl,
+ const gchar *str,
+ gint len);
+void _lm_ssl_close (LmSSL *ssl);
+void _lm_ssl_free (LmSSL *ssl);
+
+LmSSL * _lm_ssl_new (const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+void _lm_ssl_initialize (LmSSL *ssl);
+gboolean _lm_ssl_begin (LmSSL *ssl,
+ gint fd,
+ const gchar *server,
+ GError **error);
+GIOStatus _lm_ssl_read (LmSSL *ssl,
+ gchar *buf,
+ gint len,
+ gsize *bytes_read);
+gint _lm_ssl_send (LmSSL *ssl,
+ const gchar *str,
+ gint len);
+void _lm_ssl_close (LmSSL *ssl);
+void _lm_ssl_free (LmSSL *ssl);
+
+#endif /* __LM_SSL_INTERNALS_H__ */
--- a/loudmouth/lm-ssl.c Wed Apr 05 13:19:47 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,435 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Copyright (C) 2003-2004 Imendio AB
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <config.h>
-
-#include "lm-internals.h"
-
-#include <string.h>
-#include <glib.h>
-
-#include "lm-error.h"
-
-#ifdef HAVE_GNUTLS
-#include <gnutls/x509.h>
-#endif
-
-struct _LmSSL {
- LmSSLFunction func;
- gpointer func_data;
- GDestroyNotify data_notify;
- gchar *expected_fingerprint;
- char fingerprint[20];
-
- gint ref_count;
-#ifdef HAVE_GNUTLS
- gnutls_session gnutls_session;
- gnutls_certificate_client_credentials gnutls_xcred;
-#endif
-};
-
-static void ssl_free (LmSSL *ssl);
-
-static LmSSLResponse ssl_func_always_continue (LmSSL *ssl,
- LmSSLStatus status,
- gpointer user_data);
-
-#ifdef HAVE_GNUTLS
-static gboolean ssl_verify_certificate (LmSSL *ssl,
- const gchar *server);
-
-static gboolean
-ssl_verify_certificate (LmSSL *ssl, const gchar *server)
-{
- int status;
-
- /* This verification function uses the trusted CAs in the credentials
- * structure. So you must have installed one or more CA certificates.
- */
- status = gnutls_certificate_verify_peers (ssl->gnutls_session);
-
- if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) {
- if (ssl->func (ssl,
- LM_SSL_STATUS_NO_CERT_FOUND,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- if (status & GNUTLS_CERT_INVALID
- || status & GNUTLS_CERT_REVOKED) {
- if (ssl->func (ssl, LM_SSL_STATUS_UNTRUSTED_CERT,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- if (gnutls_certificate_expiration_time_peers (ssl->gnutls_session) < time (0)) {
- if (ssl->func (ssl, LM_SSL_STATUS_CERT_EXPIRED,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- if (gnutls_certificate_activation_time_peers (ssl->gnutls_session) > time (0)) {
- if (ssl->func (ssl, LM_SSL_STATUS_CERT_NOT_ACTIVATED,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- if (gnutls_certificate_type_get (ssl->gnutls_session) == GNUTLS_CRT_X509) {
- const gnutls_datum* cert_list;
- guint cert_list_size;
- size_t digest_size;
- gnutls_x509_crt cert;
-
- cert_list = gnutls_certificate_get_peers (ssl->gnutls_session, &cert_list_size);
- if (cert_list == NULL) {
- if (ssl->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- gnutls_x509_crt_init (&cert);
-
- if (!gnutls_x509_crt_import (cert, &cert_list[0],
- GNUTLS_X509_FMT_DER)) {
- if (ssl->func (ssl, LM_SSL_STATUS_NO_CERT_FOUND,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- if (!gnutls_x509_crt_check_hostname (cert, server)) {
- if (ssl->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- gnutls_x509_crt_deinit (cert);
-
- if (gnutls_fingerprint (GNUTLS_DIG_MD5, &cert_list[0],
- ssl->fingerprint,
- &digest_size) >= 0) {
- if (ssl->expected_fingerprint &&
- memcmp (ssl->expected_fingerprint, ssl->fingerprint,
- digest_size) &&
- ssl->func (ssl,
- LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
- else if (ssl->func (ssl, LM_SSL_STATUS_GENERIC_ERROR,
- ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-void
-_lm_ssl_initialize (LmSSL *ssl)
-{
- gnutls_global_init ();
- gnutls_certificate_allocate_credentials (&ssl->gnutls_xcred);
-}
-
-gboolean
-_lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error)
-{
- int ret;
- gboolean auth_ok = TRUE;
- const int cert_type_priority[2] =
- { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP };
-
- gnutls_init (&ssl->gnutls_session, GNUTLS_CLIENT);
- gnutls_set_default_priority (ssl->gnutls_session);
- gnutls_certificate_type_set_priority (ssl->gnutls_session,
- cert_type_priority);
- gnutls_credentials_set (ssl->gnutls_session,
- GNUTLS_CRD_CERTIFICATE,
- ssl->gnutls_xcred);
-
- gnutls_transport_set_ptr (ssl->gnutls_session,
- (gnutls_transport_ptr) fd);
-
- ret = gnutls_handshake (ssl->gnutls_session);
-
- if (ret >= 0) {
- auth_ok = ssl_verify_certificate (ssl, server);
- }
-
- if (ret < 0 || !auth_ok) {
- char *errmsg;
-
- gnutls_perror (ret);
-
- if (!auth_ok) {
- errmsg = "*** GNUTLS authentication error";
- } else {
- errmsg = "*** GNUTLS handshake failed";
- }
-
- g_set_error (error,
- LM_ERROR, LM_ERROR_CONNECTION_OPEN,
- errmsg);
-
- return FALSE;
- }
-
- return TRUE;
-}
-
-GIOStatus
-_lm_ssl_read (LmSSL *ssl, gchar *buf, gint len, gsize *bytes_read)
-{
- GIOStatus status;
- gint b_read;
-
- *bytes_read = 0;
- b_read = gnutls_record_recv (ssl->gnutls_session, buf, len);
-
- if (b_read == GNUTLS_E_AGAIN) {
- status = G_IO_STATUS_AGAIN;
- }
- else if (b_read > len) {
- status = G_IO_STATUS_EOF;
- }
- else if (b_read < 0) {
- status = G_IO_STATUS_ERROR;
- } else {
- *bytes_read = (guint) b_read;
- status = G_IO_STATUS_NORMAL;
- }
-
- return status;
-}
-
-gint
-_lm_ssl_send (LmSSL *ssl, const gchar *str, gint len)
-{
- gint bytes_written;
-
- bytes_written = gnutls_record_send (ssl->gnutls_session, str, len);
-
- while (bytes_written < 0) {
- if (bytes_written != GNUTLS_E_INTERRUPTED &&
- bytes_written != GNUTLS_E_AGAIN) {
- return -1;
- }
-
- bytes_written = gnutls_record_send (ssl->gnutls_session,
- str, len);
- }
-
- return bytes_written;
-}
-
-void
-_lm_ssl_close (LmSSL *ssl)
-{
- gnutls_deinit (ssl->gnutls_session);
- gnutls_certificate_free_credentials (ssl->gnutls_xcred);
- gnutls_global_deinit ();
-}
-#endif
-
-static void
-ssl_free (LmSSL *ssl)
-{
- g_free (ssl->expected_fingerprint);
- g_free (ssl);
-}
-
-
-static LmSSLResponse
-ssl_func_always_continue (LmSSL *ssl,
- LmSSLStatus status,
- gpointer user_data)
-{
- return LM_SSL_RESPONSE_CONTINUE;;
-}
-
-/**
- * lm_ssl_is_supported:
- *
- * Checks whether Loudmouth supports SSL or not.
- *
- * Return value: #TRUE if this installation of Loudmouth supports SSL, otherwise returns #FALSE.
- **/
-gboolean
-lm_ssl_is_supported (void)
-{
-#ifdef HAVE_GNUTLS
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-/**
- * lm_ssl_new:
- * @expected_fingerprint: The expected fingerprint. @ssl_function will be called if there is a mismatch. %NULL if you are not interested in this check.
- * @ssl_function: Callback called to inform the user of a problem during setting up the SSL connection and how to proceed. If %NULL is passed the default function that always continues will be used.
- * @user_data: Data sent with the callback.
- * @notify: Function to free @user_dataa when the connection is finished. %NULL if @user_data should not be freed.
- *
- * Creates a new SSL struct, call #lm_connection_set_ssl to use it.
- *
- * Return value: A new #LmSSL struct.
- **/
-LmSSL *
-lm_ssl_new (const gchar *expected_fingerprint,
- LmSSLFunction ssl_function,
- gpointer user_data,
- GDestroyNotify notify)
-{
- LmSSL *ssl;
-
- ssl = g_new0 (LmSSL, 1);
-
- ssl->ref_count = 1;
- ssl->func = ssl_function;
- ssl->func_data = user_data;
- ssl->data_notify = notify;
- ssl->fingerprint[0] = '\0';
-
- if (expected_fingerprint) {
- ssl->expected_fingerprint = g_strdup (expected_fingerprint);
- } else {
- ssl->expected_fingerprint = NULL;
- }
-
- if (!ssl->func) {
- /* If user didn't provide an SSL func the default will be used
- * this function will always tell the connection to continue.
- */
- ssl->func = ssl_func_always_continue;
- }
-
- return ssl;
-}
-
-/**
- * lm_ssl_get_fingerprint:
- * @ssl: an #LmSSL
- *
- * Returns the MD5 fingerprint of the remote server's certificate.
- *
- * Return value: A 16-byte array representing the fingerprint or %NULL if unknown.
- **/
-const gchar *
-lm_ssl_get_fingerprint (LmSSL *ssl)
-{
- g_return_val_if_fail (ssl != NULL, NULL);
-
- return ssl->fingerprint;
-}
-
-/**
- * lm_ssl_ref:
- * @ssl: an #LmSSL
- *
- * Adds a reference to @ssl.
- *
- * Return value: the ssl
- **/
-LmSSL *
-lm_ssl_ref (LmSSL *ssl)
-{
- g_return_val_if_fail (ssl != NULL, NULL);
-
- ssl->ref_count++;
-
- return ssl;
-}
-
-/**
- * lm_ssl_unref
- * @ssl: an #LmSSL
- *
- * Removes a reference from @ssl. When no more references are present
- * @ssl is freed.
- **/
-void
-lm_ssl_unref (LmSSL *ssl)
-{
- g_return_if_fail (ssl != NULL);
-
- ssl->ref_count --;
-
- if (ssl->ref_count == 0) {
- if (ssl->data_notify) {
- (* ssl->data_notify) (ssl->func_data);
- }
-
- ssl_free (ssl);
- }
-}
-
-/* Define the GnuTLS functions as noops if we compile without support */
-#ifndef HAVE_GNUTLS
-
-void
-_lm_ssl_initialize (LmSSL *ssl)
-{
- /* NOOP */
-}
-
-gboolean
-_lm_ssl_begin (LmSSL *ssl,
- gint fd,
- const gchar *server,
- GError **error)
-{
- return TRUE;
-}
-
-GIOStatus
-_lm_ssl_read (LmSSL *ssl,
- gchar *buf,
- gint len,
- gsize *bytes_read)
-{
- /* NOOP */
- *bytes_read = 0;
-
- return G_IO_STATUS_EOF;
-}
-
-gboolean
-_lm_ssl_send (LmSSL *ssl, const gchar *str, gint len)
-{
- /* NOOP */
- return TRUE;
-}
-void
-_lm_ssl_close (LmSSL *ssl)
-{
- /* NOOP */
-}
-
-#endif
-
--- a/loudmouth/lm-ssl.h Wed Apr 05 13:19:47 2006 +0000
+++ b/loudmouth/lm-ssl.h Wed Apr 05 15:19:13 2006 +0000
@@ -21,6 +21,8 @@
#ifndef __LM_SSL_H__
#define __LM_SSL_H__
+#include <glib.h>
+
#if !defined (LM_INSIDE_LOUDMOUTH_H) && !defined (LM_COMPILATION)
#error "Only <loudmouth/loudmouth.h> can be included directly, this file may disappear or change contents."
#endif
@@ -28,6 +30,7 @@
G_BEGIN_DECLS
typedef struct _LmSSL LmSSL;
+
typedef enum {
LM_CERT_INVALID,
LM_CERT_ISSUER_NOT_FOUND,