052725cd14d6ddfc60ba565989313e0c65c9426c
[platform/upstream/libnice.git] / socket / pseudossl.c
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 *
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
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
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
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
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
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
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
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
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
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 }