Add support for MS Office Communicator pseudossl compatibility
authorYouness Alaoui <youness.alaoui@collabora.co.uk>
Sat, 5 Apr 2014 03:56:16 +0000 (23:56 -0400)
committerOlivier CrĂȘte <olivier.crete@ocrete.ca>
Thu, 15 May 2014 13:43:14 +0000 (09:43 -0400)
agent/agent.c
socket/pseudossl.c
socket/pseudossl.h

index b0aea57..b3edd2e 100644 (file)
@@ -1818,7 +1818,12 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
 
     if (turn->type ==  NICE_RELAY_TYPE_TURN_TLS &&
         agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
-      nicesock = nice_pseudossl_socket_new (nicesock);
+      nicesock = nice_pseudossl_socket_new (nicesock,
+          NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE);
+    } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
+        agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
+      nicesock = nice_pseudossl_socket_new (nicesock,
+          NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC);
     }
     cdisco->nicesock = nice_tcp_turn_socket_new (nicesock,
         agent_to_turn_socket_compatibility (agent));
index 6cf83d8..a0253de 100644 (file)
@@ -55,6 +55,7 @@ typedef struct {
   gboolean handshaken;
   NiceSocket *base_socket;
   GQueue send_queue;
+  NicePseudoSSLSocketCompatibility compatibility;
 } PseudoSSLPriv;
 
 
@@ -65,7 +66,7 @@ struct to_be_sent {
 };
 
 
-static const gchar SSL_SERVER_HANDSHAKE[] = {
+static const gchar SSL_SERVER_GOOGLE_HANDSHAKE[] = {
   0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
   0x46, 0x03, 0x01, 0x42, 0x85, 0x45, 0xa7, 0x27,
   0xa9, 0x5d, 0xa0, 0xb3, 0xc5, 0xe7, 0x53, 0xda,
@@ -77,7 +78,7 @@ static const gchar SSL_SERVER_HANDSHAKE[] = {
   0x30, 0x32, 0x6e, 0x38, 0x4d, 0xa2, 0x75, 0x57,
   0x41, 0x6c, 0x34, 0x5c, 0x00, 0x04, 0x00};
 
-static const gchar SSL_CLIENT_HANDSHAKE[] = {
+static const gchar SSL_CLIENT_GOOGLE_HANDSHAKE[] = {
   0x80, 0x46, 0x01, 0x03, 0x01, 0x00, 0x2d, 0x00,
   0x00, 0x00, 0x10, 0x01, 0x00, 0x80, 0x03, 0x00,
   0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x40, 0x02,
@@ -88,6 +89,27 @@ static const gchar SSL_CLIENT_HANDSHAKE[] = {
   0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc,
   0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea};
 
+static const gchar SSL_SERVER_MSOC_HANDSHAKE[] = {
+  0x16, 0x03, 0x01, 0x00, 0x4e, 0x02, 0x00, 0x00,
+  0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0e,
+  0x00, 0x00, 0x00};
+
+static const gchar SSL_CLIENT_MSOC_HANDSHAKE[] = {
+  0x16, 0x03, 0x01, 0x00, 0x2d, 0x01, 0x00, 0x00,
+  0x29, 0x03, 0x01, 0xc1, 0xfc, 0xd5, 0xa3, 0x6d,
+  0x93, 0xdd, 0x7e, 0x0b, 0x45, 0x67, 0x3f, 0xec,
+  0x79, 0x85, 0xfb, 0xbc, 0x3f, 0xd6, 0x60, 0xc2,
+  0xce, 0x84, 0x85, 0x08, 0x1b, 0x81, 0x21, 0xbc,
+  0xaa, 0x10, 0xfb, 0x00, 0x00, 0x02, 0x00, 0x18,
+  0x01, 0x00};
 
 static void socket_close (NiceSocket *sock);
 static gint socket_recv_messages (NiceSocket *sock,
@@ -104,14 +126,30 @@ static void free_to_be_sent (struct to_be_sent *tbs);
 
 
 NiceSocket *
-nice_pseudossl_socket_new (NiceSocket *base_socket)
+nice_pseudossl_socket_new (NiceSocket *base_socket,
+    NicePseudoSSLSocketCompatibility compatibility)
 {
   PseudoSSLPriv *priv;
-  NiceSocket *sock = g_slice_new0 (NiceSocket);
+  NiceSocket *sock;
+  const gchar *buf;
+  guint len;
+
+  if (compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) {
+    buf = SSL_CLIENT_MSOC_HANDSHAKE;
+    len = sizeof(SSL_CLIENT_MSOC_HANDSHAKE);
+  } else if (compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE) {
+    buf = SSL_CLIENT_GOOGLE_HANDSHAKE;
+    len = sizeof(SSL_CLIENT_GOOGLE_HANDSHAKE);
+  } else {
+    return NULL;
+  }
+
+  sock = g_slice_new0 (NiceSocket);
   sock->priv = priv = g_slice_new0 (PseudoSSLPriv);
 
   priv->handshaken = FALSE;
   priv->base_socket = base_socket;
+  priv->compatibility = compatibility;
 
   sock->type = NICE_SOCKET_TYPE_PSEUDOSSL;
   sock->fileno = priv->base_socket->fileno;
@@ -124,8 +162,7 @@ nice_pseudossl_socket_new (NiceSocket *base_socket)
 
   /* We send 'to' NULL because it will always be to an already connected
    * TCP base socket, which ignores the destination */
-  nice_socket_send_reliable (priv->base_socket, NULL,
-      sizeof(SSL_CLIENT_HANDSHAKE), SSL_CLIENT_HANDSHAKE);
+  nice_socket_send_reliable (priv->base_socket, NULL, len, buf);
 
   return sock;
 }
@@ -145,6 +182,27 @@ socket_close (NiceSocket *sock)
   g_slice_free(PseudoSSLPriv, sock->priv);
 }
 
+static gboolean
+server_handshake_valid(NiceSocket *sock, GInputVector *data)
+{
+  PseudoSSLPriv *priv = sock->priv;
+
+  if (priv->compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) {
+    if (data->size == sizeof(SSL_SERVER_MSOC_HANDSHAKE)) {
+      guint8 *buf = data->buffer;
+
+      memset(buf + 11, 0, 32);
+      memset(buf + 44, 0, 32);
+      return memcmp(SSL_SERVER_MSOC_HANDSHAKE, data->buffer,
+          sizeof(SSL_SERVER_MSOC_HANDSHAKE)) == 0;
+    }
+    return FALSE;
+  } else {
+    return data->size == sizeof(SSL_SERVER_GOOGLE_HANDSHAKE) &&
+        memcmp(SSL_SERVER_GOOGLE_HANDSHAKE, data->buffer,
+            sizeof(SSL_SERVER_GOOGLE_HANDSHAKE)) == 0;
+  }
+}
 
 static gint
 socket_recv_messages (NiceSocket *sock,
@@ -160,11 +218,18 @@ socket_recv_messages (NiceSocket *sock,
           recv_messages, n_recv_messages);
     }
   } else {
-    guint8 data[sizeof(SSL_SERVER_HANDSHAKE)];
+    guint8 data[MAX(sizeof(SSL_SERVER_GOOGLE_HANDSHAKE),
+          sizeof(SSL_SERVER_MSOC_HANDSHAKE))];
     gint ret = -1;
-    GInputVector local_recv_buf = { data, sizeof (data) };
+    GInputVector local_recv_buf = { data, sizeof(data) };
     NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
 
+
+    if (priv->compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) {
+      local_recv_buf.size = sizeof(SSL_SERVER_MSOC_HANDSHAKE);
+    } else {
+      local_recv_buf.size = sizeof(SSL_SERVER_GOOGLE_HANDSHAKE);
+    }
     if (priv->base_socket) {
       ret = nice_socket_recv_messages (priv->base_socket,
           &local_recv_message, 1);
@@ -172,9 +237,7 @@ socket_recv_messages (NiceSocket *sock,
 
     if (ret <= 0) {
       return ret;
-    } else if (ret == 1 &&
-        local_recv_buf.size == sizeof (SSL_SERVER_HANDSHAKE) &&
-        memcmp(SSL_SERVER_HANDSHAKE, data, sizeof(SSL_SERVER_HANDSHAKE)) == 0) {
+    } else if (ret == 1 && server_handshake_valid(sock, &local_recv_buf)) {
       struct to_be_sent *tbs = NULL;
       priv->handshaken = TRUE;
       while ((tbs = g_queue_pop_head (&priv->send_queue))) {
index 38ea309..e4cd879 100644 (file)
 
 G_BEGIN_DECLS
 
+/**
+ * PseudosslCompatibility:
+ * @NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE: Use google compatible pseudossl
+ * @NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC: Use compatibility for Microsoft
+ * Office Communicator and Lync servers
+ *
+ * An enum to specify which pseudo SSL compatibility mode the #NiceSocket should
+ * use.
+ */
+typedef enum
+{
+  NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE = 0,
+  NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC,
+} NicePseudoSSLSocketCompatibility;
 
 NiceSocket *
-nice_pseudossl_socket_new (NiceSocket *base_socket);
+nice_pseudossl_socket_new (NiceSocket *base_socket,
+    NicePseudoSSLSocketCompatibility compatibility);
 
 
 G_END_DECLS