adium 5099:61f9ea4acc88: workaround to retry SSL handshake with ...

commits at adium.im commits at adium.im
Tue Oct 2 18:02:40 UTC 2012


details:	http://hg.adium.im/adium/rev/61f9ea4acc88
revision:	5099:61f9ea4acc88
branch:		adium-1.5.4
author:		Evan Kinney <emkinney at gmail.com>
date:		Thu Aug 09 16:32:00 2012 -0400

workaround to retry SSL handshake with buggy servers

diffs (164 lines):

diff -r 51f7defc489c -r 61f9ea4acc88 Plugins/Purple Service/libpurple_extensions/ssl-cdsa.c
--- a/Plugins/Purple Service/libpurple_extensions/ssl-cdsa.c	Mon Sep 24 00:48:15 2012 +0200
+++ b/Plugins/Purple Service/libpurple_extensions/ssl-cdsa.c	Thu Aug 09 16:32:00 2012 -0400
@@ -70,6 +70,7 @@
 void (*query_cert_chain)(PurpleSslConnection *gsc, const char *hostname, CFArrayRef certs, void (*query_cert_cb)(gboolean trusted, void *userdata), void *userdata);
 
 static query_cert_chain certificate_ui_cb = NULL;
+static void ssl_cdsa_create_context(gpointer data);
 
 /*
  * ssl_cdsa_init
@@ -139,7 +140,67 @@
 	 * here and there.
 	 */
 	err = SSLHandshake(cdsa_data->ssl_ctx);
-	if(err != noErr) {
+    if (err == errSSLBadRecordMac) {
+        /*
+         * try explicitly forcing TLS 1.0/SSL 3.0 to (maybe) make buggy servers work
+         */
+        purple_debug_info("cdsa", "SSLHandshake reported bad MAC, forcing TLS 1.0/SSL 3.0\n");
+        
+        ssl_cdsa_close(gsc);
+        ssl_cdsa_create_context(gsc);
+        cdsa_data = PURPLE_SSL_CDSA_DATA(gsc);
+        
+        OSStatus protoErr;
+        protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kSSLProtocolAll, false);
+        if (protoErr != noErr) {
+            fprintf(stderr, "cdsa: failed to disable protocols: error %d\n",(int)protoErr);
+            purple_debug_error("cdsa", "failed to disable protocols: error %d\n",(int)protoErr);
+            if (gsc->error_cb != NULL)
+                gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,
+                              gsc->connect_cb_data);
+            
+            purple_ssl_close(gsc);
+            return;
+        }
+        protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kTLSProtocol1, true);
+        if (protoErr != noErr) {
+            fprintf(stderr, "cdsa: failed to enable TLS 1.0: error %d\n",(int)protoErr);
+            purple_debug_error("cdsa", "failed to enable TLS 1.0: error %d\n",(int)protoErr);
+            if (gsc->error_cb != NULL)
+                gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,
+                              gsc->connect_cb_data);
+            
+            purple_ssl_close(gsc);
+            return;
+        }
+        protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kSSLProtocol3, true);
+        if (protoErr != noErr) {
+            fprintf(stderr, "cdsa: failed to enable SSL 3.0: error %d\n",(int)protoErr);
+            purple_debug_error("cdsa", "failed to enable SSL 3.0: error %d\n",(int)protoErr);
+            if (gsc->error_cb != NULL)
+                gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,
+                              gsc->connect_cb_data);
+            
+            purple_ssl_close(gsc);
+            return;
+        }
+        
+        purple_debug_info("cdsa", "retrying SSLHandshake\n");
+        err = SSLHandshake(cdsa_data->ssl_ctx);
+        if (err != noErr) {
+            if(err == errSSLWouldBlock)
+                return;
+            fprintf(stderr,"cdsa: SSLHandshake failed after forcing protocol versions with error %d\n",(int)err);
+            purple_debug_error("cdsa", "SSLHandshake failed after forcing protocol versions with error %d\n",(int)err);
+            if (gsc->error_cb != NULL)
+                gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,
+                              gsc->connect_cb_data);
+            
+            purple_ssl_close(gsc);
+            return;
+        }
+        purple_debug_info("cdsa", "SSLHandshake succeeded after forcing protocol versions, continuing ssl_connect\n");
+    } else if (err != noErr) {
 		if(err == errSSLWouldBlock)
 			return;
 		fprintf(stderr,"cdsa: SSLHandshake failed with error %d\n",(int)err);
@@ -283,26 +344,22 @@
     return ortn;
 }
 
-/*
- * ssl_cdsa_connect
- *
- * given a socket, put an cdsa connection around it.
- */
 static void
-ssl_cdsa_connect(PurpleSslConnection *gsc) {
+ssl_cdsa_create_context(gpointer data) {
+    PurpleSslConnection *gsc = (PurpleSslConnection *)data;
 	PurpleSslCDSAData *cdsa_data;
     OSStatus err;
-
-	/*
+    
+    /*
 	 * allocate some memory to store variables for the cdsa connection.
 	 * the memory comes zero'd from g_new0 so we don't need to null the
 	 * pointers held in this struct.
 	 */
-	cdsa_data = g_new0(PurpleSslCDSAData, 1);
+    cdsa_data = g_new0(PurpleSslCDSAData, 1);
 	gsc->private_data = cdsa_data;
 	connections = g_list_append(connections, gsc);
-
-	/*
+    
+    /*
 	 * allocate a new SSLContextRef object
 	 */
     err = SSLNewContext(false, &cdsa_data->ssl_ctx);
@@ -310,8 +367,8 @@
 		purple_debug_error("cdsa", "SSLNewContext failed\n");
 		if (gsc->error_cb != NULL)
 			gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,
-				gsc->connect_cb_data);
-
+                          gsc->connect_cb_data);
+        
 		purple_ssl_close(gsc);
 		return;
 	}
@@ -381,8 +438,8 @@
         purple_debug_error("cdsa", "SSLSetEnabledCiphers failed\n");
         if (gsc->error_cb != NULL)
             gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,
-                       gsc->connect_cb_data);
-
+                          gsc->connect_cb_data);
+        
         purple_ssl_close(gsc);
         return;
     }
@@ -402,7 +459,7 @@
             return;
         }
     }
-
+    
 	/*
      * Disable verifying the certificate chain.
 	 * We have to do that manually later on! This is the only way to be able to continue with a connection, even though the user
@@ -415,7 +472,18 @@
     }
 	
 	cdsa_data->handshake_handler = purple_input_add(gsc->fd, PURPLE_INPUT_READ, ssl_cdsa_handshake_cb, gsc);
+}
 
+/*
+ * ssl_cdsa_connect
+ *
+ * given a socket, put an cdsa connection around it.
+ */
+static void
+ssl_cdsa_connect(PurpleSslConnection *gsc) {
+	
+    ssl_cdsa_create_context(gsc);
+    
 	// calling this here relys on the fact that SSLHandshake has to be called at least twice
 	// to get an actual connection (first time returning errSSLWouldBlock).
 	// I guess this is always the case because SSLHandshake has to send the initial greeting first, and then wait




More information about the commits mailing list