1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * (C) 2008-2009 Collabora Ltd.
5  *  Contact: Youness Alaoui
6  * (C) 2008-2009 Nokia Corporation. All rights reserved.
7  *
8  * The contents of this file are subject to the Mozilla Public License Version
9  * 1.1 (the "License"); you may not use this file except in compliance with
10  * the License. You may obtain a copy of the License at
11  * http://www.mozilla.org/MPL/
12  *
13  * Software distributed under the License is distributed on an "AS IS" basis,
14  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15  * for the specific language governing rights and limitations under the
16  * License.
17  *
18  * The Original Code is the Nice GLib ICE library.
19  *
20  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21  * Corporation. All Rights Reserved.
22  *
23  * Contributors:
24  *   Youness Alaoui, Collabora Ltd.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
28  * case the provisions of LGPL are applicable instead of those above. If you
29  * wish to allow use of your version of this file only under the terms of the
30  * LGPL and not to allow others to use your version of this file under the
31  * MPL, indicate your decision by deleting the provisions above and replace
32  * them with the notice and other provisions required by the LGPL. If you do
33  * not delete the provisions above, a recipient may use your version of this
34  * file under either the MPL or the LGPL.
35  */
36 
37 /*
38  * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
39  * http://en.wikipedia.org/wiki/Berkeley_sockets.)
40  */
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44 
45 #include "pseudossl.h"
46 #include "agent-priv.h"
47 #include "socket-priv.h"
48 
49 #include <string.h>
50 
51 #ifndef G_OS_WIN32
52 #include <unistd.h>
53 #endif
54 
55 typedef struct {
56   gboolean handshaken;
57   NiceSocket *base_socket;
58   GQueue send_queue;
59   NicePseudoSSLSocketCompatibility compatibility;
60 } PseudoSSLPriv;
61 
62 
63 static const gchar SSL_SERVER_GOOGLE_HANDSHAKE[] = {
64   0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
65   0x46, 0x03, 0x01, 0x42, 0x85, 0x45, 0xa7, 0x27,
66   0xa9, 0x5d, 0xa0, 0xb3, 0xc5, 0xe7, 0x53, 0xda,
67   0x48, 0x2b, 0x3f, 0xc6, 0x5a, 0xca, 0x89, 0xc1,
68   0x58, 0x52, 0xa1, 0x78, 0x3c, 0x5b, 0x17, 0x46,
69   0x00, 0x85, 0x3f, 0x20, 0x0e, 0xd3, 0x06, 0x72,
70   0x5b, 0x5b, 0x1b, 0x5f, 0x15, 0xac, 0x13, 0xf9,
71   0x88, 0x53, 0x9d, 0x9b, 0xe8, 0x3d, 0x7b, 0x0c,
72   0x30, 0x32, 0x6e, 0x38, 0x4d, 0xa2, 0x75, 0x57,
73   0x41, 0x6c, 0x34, 0x5c, 0x00, 0x04, 0x00};
74 
75 static const gchar SSL_CLIENT_GOOGLE_HANDSHAKE[] = {
76   0x80, 0x46, 0x01, 0x03, 0x01, 0x00, 0x2d, 0x00,
77   0x00, 0x00, 0x10, 0x01, 0x00, 0x80, 0x03, 0x00,
78   0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x40, 0x02,
79   0x00, 0x80, 0x04, 0x00, 0x80, 0x00, 0x00, 0x04,
80   0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, 0x00, 0xfe,
81   0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, 0x00,
82   0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06,
83   0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc,
84   0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea};
85 
86 static const gchar SSL_SERVER_MSOC_HANDSHAKE[] = {
87   0x16, 0x03, 0x01, 0x00, 0x4e, 0x02, 0x00, 0x00,
88   0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
89   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92   0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
93   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96   0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0e,
97   0x00, 0x00, 0x00};
98 
99 static const gchar SSL_CLIENT_MSOC_HANDSHAKE[] = {
100   0x16, 0x03, 0x01, 0x00, 0x2d, 0x01, 0x00, 0x00,
101   0x29, 0x03, 0x01, 0xc1, 0xfc, 0xd5, 0xa3, 0x6d,
102   0x93, 0xdd, 0x7e, 0x0b, 0x45, 0x67, 0x3f, 0xec,
103   0x79, 0x85, 0xfb, 0xbc, 0x3f, 0xd6, 0x60, 0xc2,
104   0xce, 0x84, 0x85, 0x08, 0x1b, 0x81, 0x21, 0xbc,
105   0xaa, 0x10, 0xfb, 0x00, 0x00, 0x02, 0x00, 0x18,
106   0x01, 0x00};
107 
108 static void socket_close (NiceSocket *sock);
109 static gint socket_recv_messages (NiceSocket *sock,
110     NiceInputMessage *recv_messages, guint n_recv_messages);
111 static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to,
112     const NiceOutputMessage *messages, guint n_messages);
113 static gint socket_send_messages_reliable (NiceSocket *sock,
114     const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages);
115 static gboolean socket_is_reliable (NiceSocket *sock);
116 static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
117 static void socket_set_writable_callback (NiceSocket *sock,
118     NiceSocketWritableCb callback, gpointer user_data);
119 static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
120 
121 NiceSocket *
nice_pseudossl_socket_new(NiceSocket * base_socket,NicePseudoSSLSocketCompatibility compatibility)122 nice_pseudossl_socket_new (NiceSocket *base_socket,
123     NicePseudoSSLSocketCompatibility compatibility)
124 {
125   PseudoSSLPriv *priv;
126   NiceSocket *sock;
127   const gchar *buf;
128   guint len;
129 
130   if (compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) {
131     buf = SSL_CLIENT_MSOC_HANDSHAKE;
132     len = sizeof(SSL_CLIENT_MSOC_HANDSHAKE);
133   } else if (compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_GOOGLE) {
134     buf = SSL_CLIENT_GOOGLE_HANDSHAKE;
135     len = sizeof(SSL_CLIENT_GOOGLE_HANDSHAKE);
136   } else {
137     return NULL;
138   }
139 
140   sock = g_slice_new0 (NiceSocket);
141   sock->priv = priv = g_slice_new0 (PseudoSSLPriv);
142 
143   priv->handshaken = FALSE;
144   priv->base_socket = base_socket;
145   priv->compatibility = compatibility;
146 
147   sock->type = NICE_SOCKET_TYPE_PSEUDOSSL;
148   sock->fileno = priv->base_socket->fileno;
149   sock->addr = priv->base_socket->addr;
150   sock->send_messages = socket_send_messages;
151   sock->send_messages_reliable = socket_send_messages_reliable;
152   sock->recv_messages = socket_recv_messages;
153   sock->is_reliable = socket_is_reliable;
154   sock->can_send = socket_can_send;
155   sock->set_writable_callback = socket_set_writable_callback;
156   sock->is_based_on = socket_is_based_on;
157   sock->close = socket_close;
158 
159   /* We send 'to' NULL because it will always be to an already connected
160    * TCP base socket, which ignores the destination */
161   nice_socket_send_reliable (priv->base_socket, NULL, len, buf);
162 
163   return sock;
164 }
165 
166 
167 static void
socket_close(NiceSocket * sock)168 socket_close (NiceSocket *sock)
169 {
170   PseudoSSLPriv *priv = sock->priv;
171 
172   if (priv->base_socket)
173     nice_socket_free (priv->base_socket);
174 
175   nice_socket_free_send_queue (&priv->send_queue);
176 
177   g_slice_free(PseudoSSLPriv, sock->priv);
178   sock->priv = NULL;
179 }
180 
181 static gboolean
server_handshake_valid(NiceSocket * sock,GInputVector * data,guint length)182 server_handshake_valid(NiceSocket *sock, GInputVector *data, guint length)
183 {
184   PseudoSSLPriv *priv = sock->priv;
185 
186   if (priv->compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) {
187     if (length == sizeof(SSL_SERVER_MSOC_HANDSHAKE)) {
188       guint8 *buf = data->buffer;
189 
190       memset(buf + 11, 0, 32);
191       memset(buf + 44, 0, 32);
192       return memcmp(SSL_SERVER_MSOC_HANDSHAKE, data->buffer,
193           sizeof(SSL_SERVER_MSOC_HANDSHAKE)) == 0;
194     }
195     return FALSE;
196   } else {
197     return length == sizeof(SSL_SERVER_GOOGLE_HANDSHAKE) &&
198         memcmp(SSL_SERVER_GOOGLE_HANDSHAKE, data->buffer,
199             sizeof(SSL_SERVER_GOOGLE_HANDSHAKE)) == 0;
200   }
201 }
202 
203 static gint
socket_recv_messages(NiceSocket * sock,NiceInputMessage * recv_messages,guint n_recv_messages)204 socket_recv_messages (NiceSocket *sock,
205     NiceInputMessage *recv_messages, guint n_recv_messages)
206 {
207   PseudoSSLPriv *priv = sock->priv;
208 
209   /* Make sure socket has not been freed: */
210   g_assert (sock->priv != NULL);
211 
212   if (priv->handshaken) {
213     if (priv->base_socket) {
214       /* Fast path: once we’ve done the handshake, pass straight through to the
215        * base socket. */
216       return nice_socket_recv_messages (priv->base_socket,
217           recv_messages, n_recv_messages);
218     }
219   } else {
220     guint8 data[MAX(sizeof(SSL_SERVER_GOOGLE_HANDSHAKE),
221           sizeof(SSL_SERVER_MSOC_HANDSHAKE))];
222     gint ret = -1;
223     GInputVector local_recv_buf = { data, sizeof(data) };
224     NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
225 
226 
227     if (priv->compatibility == NICE_PSEUDOSSL_SOCKET_COMPATIBILITY_MSOC) {
228       local_recv_buf.size = sizeof(SSL_SERVER_MSOC_HANDSHAKE);
229     } else {
230       local_recv_buf.size = sizeof(SSL_SERVER_GOOGLE_HANDSHAKE);
231     }
232     if (priv->base_socket) {
233       ret = nice_socket_recv_messages (priv->base_socket,
234           &local_recv_message, 1);
235     }
236 
237     if (ret <= 0) {
238       return ret;
239     } else if (ret == 1 && server_handshake_valid(sock, &local_recv_buf,
240             local_recv_message.length)) {
241       priv->handshaken = TRUE;
242       nice_socket_flush_send_queue (priv->base_socket, &priv->send_queue);
243     } else {
244       if (priv->base_socket)
245         nice_socket_free (priv->base_socket);
246       priv->base_socket = NULL;
247 
248       return -1;
249     }
250   }
251   return 0;
252 }
253 
254 static gint
socket_send_messages(NiceSocket * sock,const NiceAddress * to,const NiceOutputMessage * messages,guint n_messages)255 socket_send_messages (NiceSocket *sock, const NiceAddress *to,
256     const NiceOutputMessage *messages, guint n_messages)
257 {
258   PseudoSSLPriv *priv = sock->priv;
259 
260   /* Make sure socket has not been freed: */
261   g_assert (sock->priv != NULL);
262 
263   if (priv->handshaken) {
264     /* Fast path: pass directly through to the base socket once the handshake is
265      * complete. */
266     if (priv->base_socket == NULL)
267       return -1;
268 
269     return nice_socket_send_messages (priv->base_socket, to, messages,
270         n_messages);
271   } else {
272     return 0;
273   }
274   return n_messages;
275 }
276 
277 
278 static gint
socket_send_messages_reliable(NiceSocket * sock,const NiceAddress * to,const NiceOutputMessage * messages,guint n_messages)279 socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to,
280     const NiceOutputMessage *messages, guint n_messages)
281 {
282   PseudoSSLPriv *priv = sock->priv;
283 
284   if (priv->handshaken) {
285     /* Fast path: pass directly through to the base socket once the handshake is
286      * complete. */
287     if (priv->base_socket == NULL)
288       return -1;
289 
290     return nice_socket_send_messages_reliable (priv->base_socket, to, messages,
291         n_messages);
292   } else {
293     nice_socket_queue_send (&priv->send_queue, to, messages, n_messages);
294   }
295   return n_messages;
296 }
297 
298 static gboolean
socket_is_reliable(NiceSocket * sock)299 socket_is_reliable (NiceSocket *sock)
300 {
301   PseudoSSLPriv *priv = sock->priv;
302 
303   return nice_socket_is_reliable (priv->base_socket);
304 }
305 
306 static gboolean
socket_can_send(NiceSocket * sock,NiceAddress * addr)307 socket_can_send (NiceSocket *sock, NiceAddress *addr)
308 {
309   PseudoSSLPriv *priv = sock->priv;
310 
311   return nice_socket_can_send (priv->base_socket, addr);
312 }
313 
314 static void
socket_set_writable_callback(NiceSocket * sock,NiceSocketWritableCb callback,gpointer user_data)315 socket_set_writable_callback (NiceSocket *sock,
316     NiceSocketWritableCb callback, gpointer user_data)
317 {
318   PseudoSSLPriv *priv = sock->priv;
319 
320   nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
321 }
322 
323 static gboolean
socket_is_based_on(NiceSocket * sock,NiceSocket * other)324 socket_is_based_on (NiceSocket *sock, NiceSocket *other)
325 {
326   PseudoSSLPriv *priv = sock->priv;
327 
328   return (sock == other) ||
329       (priv && nice_socket_is_based_on (priv->base_socket, other));
330 }
331