2006-04-05 Mikael Hallendal <micke@imendio.com>
authorhallski <hallski>
Wed, 05 Apr 2006 15:19:13 +0000
changeset 137 18785575aa7a
parent 135 6bb0aad132e0
child 138 210cf8993393
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.
ChangeLog
configure.in
loudmouth/Makefile.am
loudmouth/lm-connection.c
loudmouth/lm-internals.h
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.c
loudmouth/lm-ssl.h
--- 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,