Hi!
Continuing to clean LmConnection up I splitted out the SSL parts. These
are now put into lm-ssl.[ch]. Instead of calling
lm_connection_set_use_ssl (...);
you will now first create an SSL structure and then pass it to
lm_connection_set_ssl (similar to how you set a proxy).
>From test-lm.c:
---------------
LmSSL *ssl;
ssl = lm_ssl_new (expected_fingerprint,
(LmSSLFunction) ssl_cb,
info,
(GDestroyNotify) free_user_info);
lm_connection_set_ssl (connection, ssl);
lm_ssl_unref (ssl);
-------------------
Tried it out and it seems to be working fine. Attaching patch if anyone
wants to try out before the CVS (really should move this to imendio svn)
has synced.
Regards,
Mikael Hallendal
--
Mikael Hallendal [email protected]
Imendio HB http://www.imendio.com
Phone: +46 (0)709 718 918
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/loudmouth/ChangeLog,v
retrieving revision 1.58
diff -u -b -B -p -r1.58 ChangeLog
--- ChangeLog 15 Jan 2004 06:18:13 -0000 1.58
+++ ChangeLog 15 Jan 2004 07:57:10 -0000
@@ -1,5 +1,23 @@
2004-01-15 Mikael Hallendal <[email protected]>
+ * loudmouth/Makefile.am:
+ - Added lm-ssl.[ch]
+ * loudmouth/lm-connection.c:
+ * loudmouth/lm-connection.h:
+ - Splitted out the SSL parts
+ - No longer contains loads of #ifdefs around tls parts
+ - Added lm_connection_[set|get]_ssl instead.
+ * loudmouth/lm-internals.h:
+ - Added _lm_ssl*
+ * loudmouth/lm-ssl.c:
+ * loudmouth/lm-ssl.h:
+ - New files, the SSL parts from LmConnection.
+ - Declares no-ops for SSL functions if compiled without support for it.
+ * loudmouth/test-lm.c:
+ - Updated for new SSL API.
+
+2004-01-15 Mikael Hallendal <[email protected]>
+
* loudmouth/lm-connection.c:
- Added Sjoerd Simons to copyright list.
Index: loudmouth/Makefile.am
===================================================================
RCS file: /cvs/gnome/loudmouth/loudmouth/Makefile.am,v
retrieving revision 1.4
diff -u -b -B -p -r1.4 Makefile.am
--- loudmouth/Makefile.am 15 Jan 2004 05:50:26 -0000 1.4
+++ loudmouth/Makefile.am 15 Jan 2004 07:57:10 -0000
@@ -23,6 +23,7 @@ libloudmouth_la_SOURCES = \
lm-internals.h \
lm-sha.c \
lm-sha.h \
+ lm-ssl.c \
lm-utils.c \
lm-proxy.c \
lm-queue.c \
@@ -37,6 +38,7 @@ libloudmouthinclude_HEADERS = \
lm-message-node.h \
lm-utils.h \
lm-proxy.h \
+ lm-ssl.h \
loudmouth.h \
$(NULL)
Index: loudmouth/lm-connection.c
===================================================================
RCS file: /cvs/gnome/loudmouth/loudmouth/lm-connection.c,v
retrieving revision 1.28
diff -u -b -B -p -r1.28 lm-connection.c
--- loudmouth/lm-connection.c 15 Jan 2004 06:18:14 -0000 1.28
+++ loudmouth/lm-connection.c 15 Jan 2004 07:57:10 -0000
@@ -21,10 +21,6 @@
#include <config.h>
-#ifdef HAVE_GNUTLS
-#include <gnutls/gnutls.h>
-#endif
-
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
@@ -73,12 +69,8 @@ struct _LmConnection {
/* Parameters */
gchar *server;
guint port;
- char fingerprint[20];
-#ifdef HAVE_GNUTLS
- gnutls_session gnutls_session;
- gnutls_certificate_client_credentials gnutls_xcred;
-#endif
+ LmSSL *ssl;
LmProxy *proxy;
@@ -105,10 +97,6 @@ struct _LmConnection {
LmCallback *disconnect_cb;
- LmSSLFunction ssl_func;
- gpointer ssl_func_data;
- gchar *expected_fingerprint;
-
LmQueue *incoming_messages;
GSource *incoming_source;
@@ -181,9 +169,6 @@ static GSource * connection_create_sourc
static void connection_signal_disconnect (LmConnection *connection,
LmDisconnectReason reason);
-static void connection_initilize_gnutls (LmConnection *connection);
-static gboolean connection_begin_ssl (LmConnection *connection,
- GError **error);
static void connection_do_connect (LmConnectData *connect_data);
@@ -280,87 +265,6 @@ connection_new_message_cb (LmParser
lm_queue_push_tail (connection->incoming_messages, m);
}
-#ifdef HAVE_GNUTLS
-static gboolean
-connection_verify_certificate (LmConnection *connection)
-{
- int status;
- LmSSLFunction ssl_function = connection->ssl_func;
-
- /* 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 (connection->gnutls_session);
-
- if (status == GNUTLS_E_NO_CERTIFICATE_FOUND)
- if (ssl_function (connection,
- LM_SSL_STATUS_NO_CERT_FOUND,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
- return FALSE;
-
- if (status & GNUTLS_CERT_INVALID
- || status & GNUTLS_CERT_NOT_TRUSTED
- || status & GNUTLS_CERT_CORRUPTED
- || status & GNUTLS_CERT_REVOKED)
- if (ssl_function (connection,
- LM_SSL_STATUS_UNTRUSTED_CERT,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
-
- return FALSE;
-
- if (gnutls_certificate_expiration_time_peers (connection->gnutls_session) < time (0)) {
- if (ssl_function (connection,
- LM_SSL_STATUS_CERT_EXPIRED,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
- return FALSE;
- }
-
- if (gnutls_certificate_activation_time_peers (connection->gnutls_session) > time (0)) {
- if (ssl_function (connection,
- LM_SSL_STATUS_CERT_NOT_ACTIVATED,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
- return FALSE;
- }
-
- if (gnutls_certificate_type_get (connection->gnutls_session) == GNUTLS_CRT_X509) {
- const gnutls_datum* cert_list;
- int cert_list_size;
- int digest_size;
-
- cert_list = gnutls_certificate_get_peers (connection->gnutls_session, &cert_list_size);
- if (cert_list == NULL) {
- if (ssl_function (connection,
- LM_SSL_STATUS_NO_CERT_FOUND,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
- return FALSE;
- }
- if (!gnutls_x509_check_certificates_hostname (&cert_list[0],
- connection->server)) {
- if (ssl_function (connection,
- LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
- return FALSE;
- }
- if (gnutls_x509_fingerprint (GNUTLS_DIG_MD5, &cert_list[0],
- connection->fingerprint,
- &digest_size) >= 0) {
- if (connection->expected_fingerprint &&
- memcmp (connection->expected_fingerprint, connection->fingerprint,
- digest_size) &&
- ssl_function (connection,
- LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
- return FALSE;
- } else if (ssl_function (connection,
- LM_SSL_STATUS_GENERIC_ERROR,
- connection->ssl_func_data) != LM_SSL_RESPONSE_CONTINUE)
- return FALSE;
- }
-
- return TRUE;
-}
-#endif
-
static gboolean
connection_succeeded (LmConnectData *connect_data)
{
@@ -390,12 +294,17 @@ connection_succeeded (LmConnectData *con
* like that */
g_io_channel_set_flags (connection->io_channel, flags, NULL);
- /* FIXME: Handle error */
- if (!connection_begin_ssl (connection, NULL)) {
+ if (connection->ssl) {
+ if (!_lm_ssl_begin (connection->ssl, connection->fd,
+ connection->server, NULL)) {
+ shutdown (connection->fd, SHUT_RDWR);
+ close (connection->fd);
+ connection_do_close (connection);
connection->fd = -1;
g_io_channel_unref(connection->io_channel);
return FALSE;
}
+ }
g_io_channel_set_close_on_unref (connection->io_channel, TRUE);
g_io_channel_set_encoding (connection->io_channel, NULL, NULL);
@@ -634,8 +542,9 @@ connection_do_open (LmConnection *connec
}
}
-
- connection_initilize_gnutls (connection);
+ if (connection->ssl) {
+ _lm_ssl_initialize (connection->ssl);
+ }
/* Prepare and do the nonblocking connection */
data = g_new (LmConnectData, 1);
@@ -671,13 +580,9 @@ connection_do_close (LmConnection *conne
connection->state = LM_CONNECTION_STATE_DISCONNECTED;
-#ifdef HAVE_GNUTLS
- if (lm_connection_get_use_ssl (connection)) {
- gnutls_deinit (connection->gnutls_session);
- gnutls_certificate_free_credentials (connection->gnutls_xcred);
- gnutls_global_deinit ();
+ if (connection->ssl) {
+ _lm_ssl_close (connection->ssl);
}
-#endif
}
@@ -694,32 +599,15 @@ connection_in_event (GIOChannel *sourc
return FALSE;
}
-#ifdef HAVE_GNUTLS
- if (lm_connection_get_use_ssl (connection)) {
- bytes_read = gnutls_record_recv (connection->gnutls_session,
- buf,IN_BUFFER_SIZE - 1);
- if (bytes_read == GNUTLS_E_AGAIN) {
- status = G_IO_STATUS_AGAIN;
- }
- else if (bytes_read <= 0) {
- status = G_IO_STATUS_ERROR;
-
- //connection_error_event (connection->io_channel,
- // G_IO_HUP,
- // connection);
- }
- else {
- status = G_IO_STATUS_NORMAL;
- }
+ if (connection->ssl) {
+ status = _lm_ssl_read (connection->ssl,
+ buf, IN_BUFFER_SIZE - 1, &bytes_read);
} else {
-#endif
status = g_io_channel_read_chars (connection->io_channel,
buf, IN_BUFFER_SIZE - 1,
&bytes_read,
NULL);
-#ifdef HAVE_GNUTLS
}
-#endif
if (status != G_IO_STATUS_NORMAL) {
gint reason;
@@ -821,23 +709,17 @@ connection_send (LmConnection *connecti
g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
"-----------------------------------\n");
-#ifdef HAVE_GNUTLS
- if (lm_connection_get_use_ssl (connection)) {
- while ((bytes_written = gnutls_record_send (connection->gnutls_session, str, len)) < 0)
- if (bytes_written != GNUTLS_E_INTERRUPTED &&
- bytes_written != GNUTLS_E_AGAIN)
- {
- connection_error_event (connection->io_channel, G_IO_HUP,
+ if (connection->ssl) {
+ if (!_lm_ssl_send (connection->ssl, str, len)) {
+
+ connection_error_event (connection->io_channel,
+ G_IO_HUP,
connection);
}
-
} else {
-#endif
g_io_channel_write_chars (connection->io_channel, str, len,
&bytes_written, NULL);
-#ifdef HAVE_GNUTLS
}
-#endif
return TRUE;
}
@@ -1113,70 +995,6 @@ connection_signal_disconnect (LmConnecti
}
}
-static void
-connection_initilize_gnutls (LmConnection *connection)
-{
-#ifdef HAVE_GNUTLS
- if (lm_connection_get_use_ssl (connection)) {
- gnutls_global_init ();
- gnutls_certificate_allocate_credentials (&connection->gnutls_xcred);
- }
-#endif
-}
-
-static gboolean
-connection_begin_ssl (LmConnection *connection, GError **error)
-{
-#ifdef HAVE_GNUTLS
- if (lm_connection_get_use_ssl (connection)) {
- int ret;
- gboolean auth_ok = TRUE;
- const int cert_type_priority[2] =
- { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP };
-
- gnutls_init (&connection->gnutls_session, GNUTLS_CLIENT);
- gnutls_set_default_priority (connection->gnutls_session);
- gnutls_certificate_type_set_priority (connection->gnutls_session,
- cert_type_priority);
- gnutls_credentials_set (connection->gnutls_session,
- GNUTLS_CRD_CERTIFICATE,
- connection->gnutls_xcred);
-
- gnutls_transport_set_ptr (connection->gnutls_session,
- (gnutls_transport_ptr) connection->fd);
-
- ret = gnutls_handshake (connection->gnutls_session);
-
- if (ret >= 0) {
- auth_ok = connection_verify_certificate (connection);
- }
-
- if (ret < 0 || !auth_ok) {
- char *errmsg;
-
- gnutls_perror (ret);
- shutdown (connection->fd, SHUT_RDWR);
- close (connection->fd);
- connection_do_close (connection);
-
- 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;
- }
-#endif
- return TRUE;
-}
-
/**
* lm_connection_new:
* @server: The hostname to the server for the connection.
@@ -1203,9 +1021,7 @@ lm_connection_new (const gchar *server)
}
connection->port = LM_CONNECTION_DEFAULT_PORT;
- connection->ssl_func = NULL;
- connection->expected_fingerprint = NULL;
- connection->fingerprint[0] = '\0';
+ connection->ssl = NULL;
connection->proxy = NULL;
connection->disconnect_cb = NULL;
connection->incoming_messages = lm_queue_new ();
@@ -1609,74 +1425,42 @@ lm_connection_set_port (LmConnection *co
}
/**
- * lm_connection_supports_ssl:
- *
- * Checks whether Loudmouth supports SSL or not.
- *
- * Return value: #TRUE if this installation of Loudmouth supports SSL, otherwise returns #FALSE.
- **/
-gboolean
-lm_connection_supports_ssl (void)
-{
-#ifdef HAVE_GNUTLS
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-/*
-* @fingerprint: the expected fingerprint of the remote cert, or %NULL
- * @ssl_function: Callback function used when an authentication error occurs.
- */
-void
-lm_connection_set_use_ssl (LmConnection *connection,
- const gchar *expected_fingerprint,
- LmSSLFunction ssl_function,
- gpointer user_data)
-{
- g_return_if_fail (connection != NULL);
-
- g_free (connection->expected_fingerprint);
-
- if (expected_fingerprint) {
- connection->expected_fingerprint =
- g_strdup (expected_fingerprint);
- }
-
- connection->ssl_func = ssl_function;
- connection->ssl_func_data = user_data;
-}
-
-/**
- * lm_connection_get_use_ssl:
+ * lm_connection_get_ssl:
* @connection: an #LmConnection
*
- * Returns if @connection is using SSL or not
+ * Returns the SSL struct if the connection is using one.
*
- * Return value: #TRUE if @connection is using SSL, #FALSE otherwise.
+ * Return value: The ssl struct or %NULL if no proxy is used.
**/
-gboolean
-lm_connection_get_use_ssl (LmConnection *connection)
+LmSSL *
+lm_connection_get_ssl (LmConnection *connection)
{
- g_return_val_if_fail (connection != NULL, FALSE);
+ g_return_val_if_fail (connection != NULL, NULL);
- return connection->ssl_func != NULL;
+ return connection->ssl;
}
/**
- * lm_connection_get_fingerprint:
- * @connection: an #LmConnection
+ * lm_connection_set_ssl:
+ * @connection: An #LmConnection
+ * @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 unsigned char *
-lm_connection_get_fingerprint (LmConnection *connection)
+ * Sets SSL struct or unset if @ssl is %NULL. If set @connection will use SSL to for the connection.
+ */
+void
+lm_connection_set_ssl (LmConnection *connection, LmSSL *ssl)
{
- g_return_val_if_fail (connection != NULL, NULL);
+ g_return_if_fail (connection != NULL);
- return (unsigned char*) connection->fingerprint;
+ if (connection->ssl) {
+ lm_ssl_unref (connection->ssl);
+ }
+
+ if (ssl) {
+ connection->ssl = lm_ssl_ref (ssl);
+ } else {
+ connection->ssl = NULL;
+ }
}
/**
Index: loudmouth/lm-connection.h
===================================================================
RCS file: /cvs/gnome/loudmouth/loudmouth/lm-connection.h,v
retrieving revision 1.10
diff -u -b -B -p -r1.10 lm-connection.h
--- loudmouth/lm-connection.h 15 Jan 2004 05:50:26 -0000 1.10
+++ loudmouth/lm-connection.h 15 Jan 2004 07:57:10 -0000
@@ -26,8 +26,9 @@
#error "Only <loudmouth/loudmouth.h> can be included directly, this file may di\sappear or change contents."
#endif
-#include <loudmouth/lm-proxy.h>
#include <loudmouth/lm-message.h>
+#include <loudmouth/lm-proxy.h>
+#include <loudmouth/lm-ssl.h>
#define LM_CONNECTION(o) (LmConnection *) o;
@@ -58,27 +59,6 @@ typedef enum {
} LmDisconnectReason;
typedef enum {
- LM_CERT_INVALID,
- LM_CERT_ISSUER_NOT_FOUND,
- LM_CERT_REVOKED,
-} LmCertificateStatus;
-
-typedef enum {
- LM_SSL_STATUS_NO_CERT_FOUND,
- LM_SSL_STATUS_UNTRUSTED_CERT,
- LM_SSL_STATUS_CERT_EXPIRED,
- LM_SSL_STATUS_CERT_NOT_ACTIVATED,
- LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
- LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
- LM_SSL_STATUS_GENERIC_ERROR,
-} LmSSLStatus;
-
-typedef enum {
- LM_SSL_RESPONSE_CONTINUE,
- LM_SSL_RESPONSE_STOP,
-} LmSSLResponse;
-
-typedef enum {
LM_CONNECTION_STATE_DISCONNECTED,
LM_CONNECTION_STATE_CONNECTING,
LM_CONNECTION_STATE_CONNECTED,
@@ -94,11 +74,6 @@ typedef void (* LmDisconnectFun
LmDisconnectReason reason,
gpointer user_data);
-typedef LmSSLResponse (* LmSSLFunction) (LmConnection *connection,
- LmSSLStatus status,
- gpointer user_data);
-
-
LmConnection *lm_connection_new (const gchar *server);
gboolean lm_connection_open (LmConnection *connection,
LmResultFunction function,
@@ -138,15 +113,10 @@ void lm_connection_set_server
guint lm_connection_get_port (LmConnection *connection);
void lm_connection_set_port (LmConnection *connection,
guint port);
-gboolean lm_connection_supports_ssl (void);
-void lm_connection_set_use_ssl (LmConnection *connection,
- const gchar *expected_fingerprint,
- LmSSLFunction ssl_function,
- gpointer user_data);
-gboolean lm_connection_get_use_ssl (LmConnection *connection);
-const unsigned char *
-lm_connection_get_fingerprint (LmConnection *connection);
+LmSSL * lm_connection_get_ssl (LmConnection *connection);
+void lm_connection_set_ssl (LmConnection *connection,
+ LmSSL *ssl);
LmProxy * lm_connection_get_proxy (LmConnection *connection);
void lm_connection_set_proxy (LmConnection *connection,
Index: loudmouth/lm-internals.h
===================================================================
RCS file: /cvs/gnome/loudmouth/loudmouth/lm-internals.h,v
retrieving revision 1.6
diff -u -b -B -p -r1.6 lm-internals.h
--- loudmouth/lm-internals.h 15 Jan 2004 05:50:26 -0000 1.6
+++ loudmouth/lm-internals.h 15 Jan 2004 07:57:10 -0000
@@ -52,6 +52,19 @@ gboolean _lm_proxy_negotiate
gint fd,
const gchar *server,
guint port);
+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,
+ gint *bytes_read);
+gboolean _lm_ssl_send (LmSSL *ssl,
+ const gchar *str,
+ gint len);
+void _lm_ssl_close (LmSSL *ssl);
LmHandlerResult
_lm_message_handler_handle_message (LmMessageHandler *handler,
Index: loudmouth/lm-ssl.c
===================================================================
RCS file: loudmouth/lm-ssl.c
diff -N loudmouth/lm-ssl.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ loudmouth/lm-ssl.c 15 Jan 2004 07:57:10 -0000
@@ -0,0 +1,375 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2004 Imendio HB
+ * Copyright (C) 2003 Colin Walters <[email protected]>
+ *
+ * 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/gnutls.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);
+
+#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_NOT_TRUSTED
+ || status & GNUTLS_CERT_CORRUPTED
+ || 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;
+ int cert_list_size;
+ int digest_size;
+
+ 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;
+ }
+ }
+
+ if (!gnutls_x509_check_certificates_hostname (&cert_list[0],
+ server)) {
+ if (ssl->func (ssl, LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
+ ssl->func_data) != LM_SSL_RESPONSE_CONTINUE) {
+ return FALSE;
+ }
+ }
+
+ if (gnutls_x509_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, gint *bytes_read)
+{
+ GIOStatus status;
+
+ *bytes_read = gnutls_record_recv (ssl->gnutls_session, buf, len);
+
+ if (*bytes_read == GNUTLS_E_AGAIN) {
+ status = G_IO_STATUS_AGAIN;
+ }
+ else if (*bytes_read <= 0) {
+ status = G_IO_STATUS_ERROR;
+ } else {
+ status = G_IO_STATUS_NORMAL;
+ }
+
+ return status;
+}
+
+gboolean
+_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 FALSE;
+ }
+
+ bytes_written = gnutls_record_send (ssl->gnutls_session,
+ str, len);
+ }
+
+ return TRUE;
+}
+
+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);
+}
+
+/**
+ * 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
+}
+
+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;
+ }
+
+ 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 unsigned char *
+lm_ssl_get_fingerprint (LmSSL *ssl)
+{
+ g_return_val_if_fail (ssl != NULL, NULL);
+
+ return (unsigned char*) ssl->fingerprint;
+}
+
+LmSSL *
+lm_ssl_ref (LmSSL *ssl)
+{
+ g_return_val_if_fail (ssl != NULL, NULL);
+
+ ssl->ref_count++;
+
+ return ssl;
+}
+
+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,
+ gint *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
+
Index: loudmouth/lm-ssl.h
===================================================================
RCS file: loudmouth/lm-ssl.h
diff -N loudmouth/lm-ssl.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ loudmouth/lm-ssl.h 15 Jan 2004 07:57:11 -0000
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2004 Imendio HB
+ * Copyright (C) 2003-2004 Sjoerd Simons <[email protected]>
+ *
+ * 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_H__
+#define __LM_SSL_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
+
+typedef struct _LmSSL LmSSL;
+typedef enum {
+ LM_CERT_INVALID,
+ LM_CERT_ISSUER_NOT_FOUND,
+ LM_CERT_REVOKED,
+} LmCertificateStatus;
+
+typedef enum {
+ LM_SSL_STATUS_NO_CERT_FOUND,
+ LM_SSL_STATUS_UNTRUSTED_CERT,
+ LM_SSL_STATUS_CERT_EXPIRED,
+ LM_SSL_STATUS_CERT_NOT_ACTIVATED,
+ LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
+ LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH,
+ LM_SSL_STATUS_GENERIC_ERROR,
+} LmSSLStatus;
+
+typedef enum {
+ LM_SSL_RESPONSE_CONTINUE,
+ LM_SSL_RESPONSE_STOP,
+} LmSSLResponse;
+
+typedef LmSSLResponse (* LmSSLFunction) (LmSSL *ssl,
+ LmSSLStatus status,
+ gpointer user_data);
+
+LmSSL *
+lm_ssl_new (const gchar *expected_fingerprint,
+ LmSSLFunction ssl_function,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+gboolean lm_ssl_is_supported (void);
+
+const unsigned char * lm_ssl_get_fingerprint (LmSSL *ssl);
+
+
+LmSSL * lm_ssl_ref (LmSSL *ssl);
+void lm_ssl_unref (LmSSL *ssl);
+
+#endif /* __LM_SSL_H__ */
Index: loudmouth/test-lm.c
===================================================================
RCS file: /cvs/gnome/loudmouth/loudmouth/test-lm.c,v
retrieving revision 1.9
diff -u -b -B -p -r1.9 test-lm.c
--- loudmouth/test-lm.c 27 Dec 2003 23:01:19 -0000 1.9
+++ loudmouth/test-lm.c 15 Jan 2004 07:57:11 -0000
@@ -35,6 +35,15 @@ typedef struct {
gchar *passwd;
} UserInfo;
+static void
+free_user_info (UserInfo *info)
+{
+ g_free (info->name);
+ g_free (info->passwd);
+
+ g_free (info);
+}
+
static unsigned char expected_fingerprint[20];
static void
@@ -47,7 +56,7 @@ print_finger (const unsigned char *fpr,
}
static LmSSLResponse
-ssl_cb (LmConnection *connection, LmSSLStatus status, gpointer ud)
+ssl_cb (LmSSL *ssl, LmSSLStatus status, gpointer ud)
{
g_print ("SSL status: %d\n", status);
switch (status) {
@@ -67,7 +76,7 @@ ssl_cb (LmConnection *connection, LmSSLS
g_print ("Certificate hostname does not match expected hostname!\n");
break;
case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH: {
- const unsigned char *fpr = lm_connection_get_fingerprint (connection);
+ const unsigned char *fpr = lm_ssl_get_fingerprint (ssl);
g_print ("Certificate fingerprint does not match expected fingerprint!\n");
g_print ("Remote fingerprint: ");
print_finger (fpr, 16);
@@ -172,7 +181,7 @@ main (int argc, char **argv)
connection = lm_connection_new (argv[1]);
- if (argc > 4 && !lm_connection_supports_ssl ()) {
+ if (argc > 4 && !lm_ssl_is_supported ()) {
g_error ("No SSL support!");
exit (1);
}
@@ -192,16 +201,22 @@ main (int argc, char **argv)
if (argc > 4) {
int i;
char *p;
+ LmSSL *ssl;
+
lm_connection_set_port (connection,
LM_CONNECTION_DEFAULT_PORT_SSL);
for (i = 0, p = argv[4]; *p && *(p+1); i++, p += 3)
expected_fingerprint[i] = (unsigned char) g_ascii_strtoull (p, NULL, 16);
- lm_connection_set_use_ssl (connection,
- expected_fingerprint,
+ ssl = lm_ssl_new (expected_fingerprint,
(LmSSLFunction) ssl_cb,
- info);
+ info,
+ (GDestroyNotify) free_user_info);
+
+ lm_connection_set_ssl (connection, ssl);
+
+ lm_ssl_unref (ssl);
}
result = lm_connection_open (connection,