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