Index: lib/http_client.c
===================================================================
--- lib/http_client.c	(revision 9ff0c256ae51f2039abc36940618a5d9fe5e6ba7)
+++ lib/http_client.c	(revision 792a93b417c24a206d8995ca8bf51482f20e997e)
@@ -33,5 +33,5 @@
 
 static gboolean http_connected( gpointer data, int source, b_input_condition cond );
-static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond );
+static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond );
 static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond );
 static void http_free( struct http_request *req );
@@ -47,5 +47,5 @@
 	if( ssl )
 	{
-		req->ssl = ssl_connect( host, port, http_ssl_connected, req );
+		req->ssl = ssl_connect( host, port, TRUE, http_ssl_connected, req );
 		if( req->ssl == NULL )
 			error = 1;
@@ -163,5 +163,6 @@
 	
 error:
-	req->status_string = g_strdup( "Error while writing HTTP request" );
+	if( req->status_string == NULL )
+		req->status_string = g_strdup( "Error while writing HTTP request" );
 	
 	req->func( req );
@@ -170,10 +171,20 @@
 }
 
-static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond )
+static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond )
 {
 	struct http_request *req = data;
 	
 	if( source == NULL )
+	{
+		if( returncode != 0 )
+		{
+			char *err = ssl_verify_strerror( returncode );
+			req->status_string = g_strdup_printf(
+				"Certificate verification problem 0x%x: %s",
+				returncode, err ? err : "Unknown" );
+			g_free( err );
+		}
 		return http_connected( data, -1, cond );
+	}
 	
 	req->fd = ssl_getfd( source );
@@ -439,5 +450,5 @@
 		if( new_proto == PROTO_HTTPS )
 		{
-			req->ssl = ssl_connect( new_host, new_port, http_ssl_connected, req );
+			req->ssl = ssl_connect( new_host, new_port, TRUE, http_ssl_connected, req );
 			if( req->ssl == NULL )
 				error = 1;
Index: lib/ssl_bogus.c
===================================================================
--- lib/ssl_bogus.c	(revision 9ff0c256ae51f2039abc36940618a5d9fe5e6ba7)
+++ lib/ssl_bogus.c	(revision 792a93b417c24a206d8995ca8bf51482f20e997e)
@@ -32,5 +32,5 @@
 }
 
-void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
+void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
 {
 	return( NULL );
@@ -56,5 +56,5 @@
 }
 
-void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) 
+void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data ) 
 {
 	return NULL;
@@ -70,2 +70,7 @@
 	return 0;
 }
+
+char *ssl_verify_strerror( int code )
+{
+	return NULL;
+}
Index: lib/ssl_client.h
===================================================================
--- lib/ssl_client.h	(revision 9ff0c256ae51f2039abc36940618a5d9fe5e6ba7)
+++ lib/ssl_client.h	(revision 792a93b417c24a206d8995ca8bf51482f20e997e)
@@ -37,12 +37,23 @@
 /* Some generic error codes. Especially SSL_AGAIN is important if you
    want to do asynchronous I/O. */
+#define NSS_VERIFY_ERROR -2
+#define OPENSSL_VERIFY_ERROR -1
 #define SSL_OK            0
 #define SSL_NOHANDSHAKE   1
 #define SSL_AGAIN         2
+#define VERIFY_CERT_ERROR 2
+#define VERIFY_CERT_INVALID 4
+#define VERIFY_CERT_REVOKED 8
+#define VERIFY_CERT_SIGNER_NOT_FOUND 16
+#define VERIFY_CERT_SIGNER_NOT_CA 32
+#define VERIFY_CERT_INSECURE_ALGORITHM 64
+#define VERIFY_CERT_NOT_ACTIVATED 128
+#define VERIFY_CERT_EXPIRED 256
+#define VERIFY_CERT_WRONG_HOSTNAME 512
 
 extern int ssl_errno;
 
 /* This is what your callback function should look like. */
-typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition);
+typedef gboolean (*ssl_input_function)(gpointer, int, void*, b_input_condition);
 
 
@@ -53,9 +64,9 @@
    ready to be used for SSL traffic. This is all done asynchronously, no
    blocking I/O! (Except for the DNS lookups, for now...) */
-G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data );
+G_MODULE_EXPORT void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data );
 
 /* Start an SSL session on an existing fd. Useful for STARTTLS functionality,
    for example in Jabber. */
-G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer data );
+G_MODULE_EXPORT void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data );
 
 /* Obviously you need special read/write functions to read data. */
@@ -90,3 +101,7 @@
 G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn );
 
+/* Converts a verification bitfield passed to ssl_input_function into
+   a more useful string. Or NULL if it had no useful bits set. */
+G_MODULE_EXPORT char *ssl_verify_strerror( int code );
+
 G_MODULE_EXPORT size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res);
Index: lib/ssl_gnutls.c
===================================================================
--- lib/ssl_gnutls.c	(revision 9ff0c256ae51f2039abc36940618a5d9fe5e6ba7)
+++ lib/ssl_gnutls.c	(revision 792a93b417c24a206d8995ca8bf51482f20e997e)
@@ -25,4 +25,5 @@
 
 #include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
 #include <gcrypt.h>
 #include <fcntl.h>
@@ -32,4 +33,5 @@
 #include "sock.h"
 #include "stdlib.h"
+#include "bitlbee.h"
 
 int ssl_errno = 0;
@@ -54,4 +56,6 @@
 	gboolean established;
 	int inpa;
+	char *hostname;
+	gboolean verify;
 	
 	gnutls_session session;
@@ -74,5 +78,5 @@
 }
 
-void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
+void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
 {
 	struct scd *conn = g_new0( struct scd, 1 );
@@ -82,4 +86,6 @@
 	conn->data = data;
 	conn->inpa = -1;
+	conn->hostname = g_strdup( host );
+	conn->verify = verify && global.conf->cafile;
 	
 	if( conn->fd < 0 )
@@ -92,5 +98,5 @@
 }
 
-void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
+void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
 {
 	struct scd *conn = g_new0( struct scd, 1 );
@@ -100,4 +106,11 @@
 	conn->data = data;
 	conn->inpa = -1;
+	conn->hostname = hostname;
+	
+	/* For now, SSL verification is globally enabled by setting the cafile
+	   setting in bitlbee.conf. Commented out by default because probably
+	   not everyone has this file in the same place and plenty of folks
+	   may not have the cert of their private Jabber server in it. */
+	conn->verify = verify && global.conf->cafile;
 	
 	/* This function should be called via a (short) timeout instead of
@@ -122,4 +135,97 @@
 }
 
+static int verify_certificate_callback( gnutls_session_t session )
+{
+	unsigned int status;
+	const gnutls_datum_t *cert_list;
+	unsigned int cert_list_size;
+	int gnutlsret;
+	int verifyret = 0;
+	gnutls_x509_crt_t cert;
+	const char *hostname;
+	
+	hostname = gnutls_session_get_ptr(session );
+
+	gnutlsret = gnutls_certificate_verify_peers2( session, &status );
+	if( gnutlsret < 0 )
+		return VERIFY_CERT_ERROR;
+
+	if( status & GNUTLS_CERT_INVALID )
+		verifyret |= VERIFY_CERT_INVALID;
+
+	if( status & GNUTLS_CERT_REVOKED )
+		verifyret |= VERIFY_CERT_REVOKED;
+
+	if( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
+		verifyret |= VERIFY_CERT_SIGNER_NOT_FOUND;
+
+	if( status & GNUTLS_CERT_SIGNER_NOT_CA )
+		verifyret |= VERIFY_CERT_SIGNER_NOT_CA;
+
+	if( status & GNUTLS_CERT_INSECURE_ALGORITHM )
+		verifyret |= VERIFY_CERT_INSECURE_ALGORITHM;
+
+	if( status & GNUTLS_CERT_NOT_ACTIVATED )
+		verifyret |= VERIFY_CERT_NOT_ACTIVATED;
+
+	if( status & GNUTLS_CERT_EXPIRED )
+		verifyret |= VERIFY_CERT_EXPIRED;
+
+	/* The following check is already performed inside 
+	 * gnutls_certificate_verify_peers2, so we don't need it.
+
+	 * if( gnutls_certificate_type_get( session ) != GNUTLS_CRT_X509 )
+	 * return GNUTLS_E_CERTIFICATE_ERROR;
+	 */
+
+	if( gnutls_x509_crt_init( &cert ) < 0 )
+		return VERIFY_CERT_ERROR;
+
+	cert_list = gnutls_certificate_get_peers( session, &cert_list_size );
+	if( cert_list == NULL || gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER ) < 0 )
+		return VERIFY_CERT_ERROR;
+
+	if( !gnutls_x509_crt_check_hostname( cert, hostname ) )
+	{
+		verifyret |= VERIFY_CERT_INVALID;
+		verifyret |= VERIFY_CERT_WRONG_HOSTNAME;
+	}
+
+	gnutls_x509_crt_deinit( cert );
+
+	return verifyret;
+}
+
+char *ssl_verify_strerror( int code )
+{
+	GString *ret = g_string_new( "" );
+	
+	if( code & VERIFY_CERT_REVOKED )
+		g_string_append( ret, "certificate has been revoked, " );
+	if( code & VERIFY_CERT_SIGNER_NOT_FOUND )
+		g_string_append( ret, "certificate hasn't got a known issuer, " );
+	if( code & VERIFY_CERT_SIGNER_NOT_CA )
+		g_string_append( ret, "certificate's issuer is not a CA, " );
+	if( code & VERIFY_CERT_INSECURE_ALGORITHM )
+		g_string_append( ret, "certificate uses an insecure algorithm, " );
+	if( code & VERIFY_CERT_NOT_ACTIVATED )
+		g_string_append( ret, "certificate has not been activated, " );
+	if( code & VERIFY_CERT_EXPIRED )
+		g_string_append( ret, "certificate has expired, " );
+	if( code & VERIFY_CERT_WRONG_HOSTNAME )
+		g_string_append( ret, "certificate hostname mismatch, " );
+	
+	if( ret->len == 0 )
+	{
+		g_string_free( ret, TRUE );
+		return NULL;
+	}
+	else
+	{
+		g_string_truncate( ret, ret->len - 2 );
+		return g_string_free( ret, FALSE );
+	}
+}
+
 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
 {
@@ -128,5 +234,5 @@
 	if( source == -1 )
 	{
-		conn->func( conn->data, NULL, cond );
+		conn->func( conn->data, 0, NULL, cond );
 		g_free( conn );
 		return FALSE;
@@ -136,5 +242,13 @@
 	
 	gnutls_certificate_allocate_credentials( &conn->xcred );
+	if( conn->verify && global.conf->cafile )
+	{
+		gnutls_certificate_set_x509_trust_file( conn->xcred, global.conf->cafile, GNUTLS_X509_FMT_PEM );
+		gnutls_certificate_set_verify_flags( conn->xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT );
+	}
+
 	gnutls_init( &conn->session, GNUTLS_CLIENT );
+	if( conn->verify )
+		gnutls_session_set_ptr( conn->session, (void *) conn->hostname );
 #if GNUTLS_VERSION_NUMBER < 0x020c00
 	gnutls_transport_set_lowat( conn->session, 0 );
@@ -152,5 +266,5 @@
 {
 	struct scd *conn = data;
-	int st;
+	int st, stver;
 	
 	if( ( st = gnutls_handshake( conn->session ) ) < 0 )
@@ -163,5 +277,5 @@
 		else
 		{
-			conn->func( conn->data, NULL, cond );
+			conn->func( conn->data, 0, NULL, cond );
 			
 			gnutls_deinit( conn->session );
@@ -174,9 +288,22 @@
 	else
 	{
-		/* For now we can't handle non-blocking perfectly everywhere... */
-		sock_make_blocking( conn->fd );
+		if( conn->verify && ( stver = verify_certificate_callback( conn->session ) ) != 0 )
+		{
+			conn->func( conn->data, stver, NULL, cond );
+
+			gnutls_deinit( conn->session );
+			gnutls_certificate_free_credentials( conn->xcred );
+			closesocket( conn->fd );
+
+			g_free( conn );
+		}
+		else
+		{
+			/* For now we can't handle non-blocking perfectly everywhere... */
+			sock_make_blocking( conn->fd );
 		
-		conn->established = TRUE;
-		conn->func( conn->data, conn, cond );
+			conn->established = TRUE;
+			conn->func( conn->data, 0, conn, cond );
+		}
 	}
 	
Index: lib/ssl_nss.c
===================================================================
--- lib/ssl_nss.c	(revision 9ff0c256ae51f2039abc36940618a5d9fe5e6ba7)
+++ lib/ssl_nss.c	(revision 792a93b417c24a206d8995ca8bf51482f20e997e)
@@ -52,4 +52,5 @@
 	PRFileDesc *prfd;
 	gboolean established;
+	gboolean verify;
 };
 
@@ -102,5 +103,5 @@
 }
 
-void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
+void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
 {
 	struct scd *conn = g_new0( struct scd, 1 );
@@ -132,5 +133,5 @@
 }
 
-void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
+void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
 {
 	struct scd *conn = g_new0( struct scd, 1 );
@@ -139,4 +140,5 @@
 	conn->func = func;
 	conn->data = data;
+	conn->verify = verify;
 
 	/* This function should be called via a (short) timeout instead of
@@ -157,4 +159,16 @@
 {
 	struct scd *conn = data;
+	
+	/* Right now we don't have any verification functionality for nss so we 
+	   fail in case verification has been requested by the user. */
+
+	if( conn->verify )
+	{
+		conn->func( conn->data, NSS_VERIFY_ERROR, NULL, cond );
+		if( source >= 0 ) closesocket( source );
+		g_free( conn );
+
+		return FALSE;
+	}
 	
 	if( source == -1 )
@@ -177,10 +191,10 @@
 	
 	conn->established = TRUE;
-	conn->func( conn->data, conn, cond );
+	conn->func( conn->data, 0, conn, cond );
 	return FALSE;
 	
 	ssl_connected_failure:
 	
-	conn->func( conn->data, NULL, cond );
+	conn->func( conn->data, 0, NULL, cond );
 	
 	PR_Close( conn -> prfd );
@@ -238,2 +252,7 @@
 	return B_EV_IO_READ;
 }
+
+char *ssl_verify_strerror( int code )
+{
+	return g_strdup( "SSL certificate verification not supported by BitlBee NSS code." );
+}
Index: lib/ssl_openssl.c
===================================================================
--- lib/ssl_openssl.c	(revision 9ff0c256ae51f2039abc36940618a5d9fe5e6ba7)
+++ lib/ssl_openssl.c	(revision 792a93b417c24a206d8995ca8bf51482f20e997e)
@@ -45,4 +45,5 @@
 	int fd;
 	gboolean established;
+	gboolean verify;
 	
 	int inpa;
@@ -64,5 +65,5 @@
 }
 
-void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
+void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
 {
 	struct scd *conn = g_new0( struct scd, 1 );
@@ -82,5 +83,5 @@
 }
 
-void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
+void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
 {
 	struct scd *conn = g_new0( struct scd, 1 );
@@ -90,4 +91,5 @@
 	conn->data = data;
 	conn->inpa = -1;
+	conn->verify = verify;
 	
 	/* This function should be called via a (short) timeout instead of
@@ -117,4 +119,16 @@
 	SSL_METHOD *meth;
 	
+	/* Right now we don't have any verification functionality for openssl so we 
+	   fail in case verification has been requested by the user. */
+
+	if( conn->verify )
+	{
+		conn->func( conn->data, OPENSSL_VERIFY_ERROR, NULL, cond );
+		if( source >= 0 ) closesocket( source );
+		g_free( conn );
+
+		return FALSE;
+	}
+
 	if( source == -1 )
 		goto ssl_connected_failure;
@@ -141,5 +155,5 @@
 
 ssl_connected_failure:
-	conn->func( conn->data, NULL, cond );
+	conn->func( conn->data, 0, NULL, cond );
 	
 	if( conn->ssl )
@@ -169,5 +183,5 @@
 		if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
 		{
-			conn->func( conn->data, NULL, cond );
+			conn->func( conn->data, 0, NULL, cond );
 			
 			SSL_shutdown( conn->ssl );
@@ -187,5 +201,5 @@
 	conn->established = TRUE;
 	sock_make_blocking( conn->fd );		/* For now... */
-	conn->func( conn->data, conn, cond );
+	conn->func( conn->data, 0, conn, cond );
 	return FALSE;
 }
@@ -272,4 +286,9 @@
 {
 	return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
+}
+
+char *ssl_verify_strerror( int code )
+{
+	return g_strdup( "SSL certificate verification not supported by BitlBee OpenSSL code." );
 }
 
