Tizen 2.0 Release
[external/libgnutls26.git] / lib / ext_server_name.c
1 /*
2  * Copyright (C) 2002, 2003, 2004, 2005, 2008, 2009, 2010 Free Software
3  * Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 #include "gnutls_int.h"
27 #include "gnutls_auth.h"
28 #include "gnutls_errors.h"
29 #include "gnutls_num.h"
30 #include <ext_server_name.h>
31
32 static int _gnutls_server_name_recv_params (gnutls_session_t session,
33                                             const opaque * data,
34                                             size_t data_size);
35 static int _gnutls_server_name_send_params (gnutls_session_t session,
36                                             opaque * data, size_t);
37
38 static int _gnutls_server_name_unpack (gnutls_buffer_st * ps,
39                                        extension_priv_data_t * _priv);
40 static int _gnutls_server_name_pack (extension_priv_data_t _priv,
41                                      gnutls_buffer_st * ps);
42 static void _gnutls_server_name_deinit_data (extension_priv_data_t priv);
43
44
45 extension_entry_st ext_mod_server_name = {
46   .name = "SERVER NAME",
47   .type = GNUTLS_EXTENSION_SERVER_NAME,
48   .parse_type = GNUTLS_EXT_APPLICATION,
49
50   .recv_func = _gnutls_server_name_recv_params,
51   .send_func = _gnutls_server_name_send_params,
52   .pack_func = _gnutls_server_name_pack,
53   .unpack_func = _gnutls_server_name_unpack,
54   .deinit_func = _gnutls_server_name_deinit_data,
55 };
56
57 /*
58  * In case of a server: if a NAME_DNS extension type is received then
59  * it stores into the session the value of NAME_DNS. The server may
60  * use gnutls_ext_get_server_name(), in order to access it.
61  *
62  * In case of a client: If a proper NAME_DNS extension type is found
63  * in the session then it sends the extension to the peer.
64  *
65  */
66 static int
67 _gnutls_server_name_recv_params (gnutls_session_t session,
68                                  const opaque * data, size_t _data_size)
69 {
70   int i;
71   const unsigned char *p;
72   uint16_t len, type;
73   ssize_t data_size = _data_size;
74   int server_names = 0;
75   server_name_ext_st *priv;
76   extension_priv_data_t epriv;
77
78   if (session->security_parameters.entity == GNUTLS_SERVER)
79     {
80       DECR_LENGTH_RET (data_size, 2, 0);
81       len = _gnutls_read_uint16 (data);
82
83       if (len != data_size)
84         {
85           /* This is unexpected packet length, but
86            * just ignore it, for now.
87            */
88           gnutls_assert ();
89           return 0;
90         }
91
92       p = data + 2;
93
94       /* Count all server_names in the packet. */
95       while (data_size > 0)
96         {
97           DECR_LENGTH_RET (data_size, 1, 0);
98           p++;
99
100           DECR_LEN (data_size, 2);
101           len = _gnutls_read_uint16 (p);
102           p += 2;
103
104           if (len > 0)
105             {
106               DECR_LENGTH_RET (data_size, len, 0);
107               server_names++;
108               p += len;
109             }
110           else
111             _gnutls_handshake_log
112               ("HSK[%p]: Received zero size server name (under attack?)\n",
113                session);
114
115         }
116
117       /* we cannot accept more server names.
118        */
119       if (server_names > MAX_SERVER_NAME_EXTENSIONS)
120         {
121           _gnutls_handshake_log
122             ("HSK[%p]: Too many server names received (under attack?)\n",
123              session);
124           server_names = MAX_SERVER_NAME_EXTENSIONS;
125         }
126
127       if (server_names == 0)
128         return 0;               /* no names found */
129
130       priv = gnutls_calloc (1, sizeof (*priv));
131       if (priv == NULL)
132         {
133           gnutls_assert ();
134           return GNUTLS_E_MEMORY_ERROR;
135         }
136
137       priv->server_names_size = server_names;
138
139       p = data + 2;
140       for (i = 0; i < server_names; i++)
141         {
142           type = *p;
143           p++;
144
145           len = _gnutls_read_uint16 (p);
146           p += 2;
147
148           switch (type)
149             {
150             case 0:            /* NAME_DNS */
151               if (len <= MAX_SERVER_NAME_SIZE)
152                 {
153                   memcpy (priv->server_names[i].name, p, len);
154                   priv->server_names[i].name_length = len;
155                   priv->server_names[i].type = GNUTLS_NAME_DNS;
156                   break;
157                 }
158             }
159
160           /* move to next record */
161           p += len;
162         }
163
164       epriv.ptr = priv;
165       _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_SERVER_NAME,
166                                     epriv);
167
168     }
169
170   return 0;
171 }
172
173 /* returns data_size or a negative number on failure
174  */
175 static int
176 _gnutls_server_name_send_params (gnutls_session_t session,
177                                  opaque * data, size_t _data_size)
178 {
179   uint16_t len;
180   opaque *p;
181   unsigned i;
182   ssize_t data_size = _data_size;
183   int total_size = 0, ret;
184   server_name_ext_st *priv;
185   extension_priv_data_t epriv;
186
187   ret =
188     _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SERVER_NAME,
189                                   &epriv);
190   if (ret < 0)
191     return 0;
192
193
194   /* this function sends the client extension data (dnsname)
195    */
196   if (session->security_parameters.entity == GNUTLS_CLIENT)
197     {
198       priv = epriv.ptr;
199
200       if (priv->server_names_size == 0)
201         return 0;
202
203       /* uint16_t
204        */
205       total_size = 2;
206       for (i = 0; i < priv->server_names_size; i++)
207         {
208           /* count the total size
209            */
210           len = priv->server_names[i].name_length;
211
212           /* uint8_t + uint16_t + size
213            */
214           total_size += 1 + 2 + len;
215         }
216
217       p = data;
218
219       /* UINT16: write total size of all names
220        */
221       DECR_LENGTH_RET (data_size, 2, GNUTLS_E_SHORT_MEMORY_BUFFER);
222       _gnutls_write_uint16 (total_size - 2, p);
223       p += 2;
224       for (i = 0; i < priv->server_names_size; i++)
225         {
226
227           switch (priv->server_names[i].type)
228             {
229             case GNUTLS_NAME_DNS:
230               len = priv->server_names[i].name_length;
231               if (len == 0)
232                 break;
233
234               /* UINT8: type of this extension
235                * UINT16: size of the first name
236                * LEN: the actual server name.
237                */
238               DECR_LENGTH_RET (data_size, len + 3,
239                                GNUTLS_E_SHORT_MEMORY_BUFFER);
240
241               *p = 0;           /* NAME_DNS type */
242               p++;
243
244               _gnutls_write_uint16 (len, p);
245               p += 2;
246
247               memcpy (p, priv->server_names[i].name, len);
248               p += len;
249               break;
250             default:
251               gnutls_assert ();
252               return GNUTLS_E_INTERNAL_ERROR;
253             }
254         }
255     }
256
257   return total_size;
258 }
259
260 /**
261  * gnutls_server_name_get:
262  * @session: is a #gnutls_session_t structure.
263  * @data: will hold the data
264  * @data_length: will hold the data length. Must hold the maximum size of data.
265  * @type: will hold the server name indicator type
266  * @indx: is the index of the server_name
267  *
268  * This function will allow you to get the name indication (if any), a
269  * client has sent.  The name indication may be any of the enumeration
270  * gnutls_server_name_type_t.
271  *
272  * If @type is GNUTLS_NAME_DNS, then this function is to be used by
273  * servers that support virtual hosting, and the data will be a null
274  * terminated UTF-8 string.
275  *
276  * If @data has not enough size to hold the server name
277  * GNUTLS_E_SHORT_MEMORY_BUFFER is returned, and @data_length will
278  * hold the required size.
279  *
280  * @index is used to retrieve more than one server names (if sent by
281  * the client).  The first server name has an index of 0, the second 1
282  * and so on.  If no name with the given index exists
283  * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
284  *
285  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
286  *   otherwise an error code is returned.
287  **/
288 int
289 gnutls_server_name_get (gnutls_session_t session, void *data,
290                         size_t * data_length,
291                         unsigned int *type, unsigned int indx)
292 {
293   char *_data = data;
294   server_name_ext_st *priv;
295   int ret;
296   extension_priv_data_t epriv;
297
298   if (session->security_parameters.entity == GNUTLS_CLIENT)
299     {
300       gnutls_assert ();
301       return GNUTLS_E_INVALID_REQUEST;
302     }
303
304   ret =
305     _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SERVER_NAME,
306                                   &epriv);
307   if (ret < 0)
308     {
309       gnutls_assert ();
310       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
311     }
312
313   priv = epriv.ptr;
314
315   if (indx + 1 > priv->server_names_size)
316     {
317       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
318     }
319
320   *type = priv->server_names[indx].type;
321
322   if (*data_length >            /* greater since we need one extra byte for the null */
323       priv->server_names[indx].name_length)
324     {
325       *data_length = priv->server_names[indx].name_length;
326       memcpy (data, priv->server_names[indx].name, *data_length);
327
328       if (*type == GNUTLS_NAME_DNS)     /* null terminate */
329         _data[(*data_length)] = 0;
330
331     }
332   else
333     {
334       *data_length = priv->server_names[indx].name_length;
335       return GNUTLS_E_SHORT_MEMORY_BUFFER;
336     }
337
338   return 0;
339 }
340
341 /**
342  * gnutls_server_name_set:
343  * @session: is a #gnutls_session_t structure.
344  * @type: specifies the indicator type
345  * @name: is a string that contains the server name.
346  * @name_length: holds the length of name
347  *
348  * This function is to be used by clients that want to inform (via a
349  * TLS extension mechanism) the server of the name they connected to.
350  * This should be used by clients that connect to servers that do
351  * virtual hosting.
352  *
353  * The value of @name depends on the @type type.  In case of
354  * %GNUTLS_NAME_DNS, an ASCII zero-terminated domain name string,
355  * without the trailing dot, is expected.  IPv4 or IPv6 addresses are
356  * not permitted.
357  *
358  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
359  *   otherwise an error code is returned.
360  **/
361 int
362 gnutls_server_name_set (gnutls_session_t session,
363                         gnutls_server_name_type_t type,
364                         const void *name, size_t name_length)
365 {
366   int server_names, ret;
367   server_name_ext_st *priv;
368   extension_priv_data_t epriv;
369   int set = 0;
370
371   if (session->security_parameters.entity == GNUTLS_SERVER)
372     {
373       gnutls_assert ();
374       return GNUTLS_E_INVALID_REQUEST;
375     }
376
377   if (name_length > MAX_SERVER_NAME_SIZE)
378     return GNUTLS_E_SHORT_MEMORY_BUFFER;
379
380   ret =
381     _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SERVER_NAME,
382                                   &epriv);
383   if (ret < 0)
384     {
385       set = 1;
386     }
387
388   if (set != 0)
389     {
390       priv = gnutls_calloc (1, sizeof (*priv));
391       if (priv == NULL)
392         {
393           gnutls_assert ();
394           return GNUTLS_E_MEMORY_ERROR;
395         }
396       epriv.ptr = priv;
397     }
398   else
399     priv = epriv.ptr;
400
401   server_names = priv->server_names_size + 1;
402
403   if (server_names > MAX_SERVER_NAME_EXTENSIONS)
404     server_names = MAX_SERVER_NAME_EXTENSIONS;
405
406   priv->server_names[server_names - 1].type = type;
407   memcpy (priv->server_names[server_names - 1].name, name, name_length);
408   priv->server_names[server_names - 1].name_length = name_length;
409
410   priv->server_names_size++;
411
412   if (set != 0)
413     _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_SERVER_NAME,
414                                   epriv);
415
416   return 0;
417 }
418
419 static void
420 _gnutls_server_name_deinit_data (extension_priv_data_t priv)
421 {
422   gnutls_free (priv.ptr);
423 }
424
425 static int
426 _gnutls_server_name_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
427 {
428   server_name_ext_st *priv = epriv.ptr;
429   int i, ret;
430
431   BUFFER_APPEND_NUM (ps, priv->server_names_size);
432   for (i = 0; i < priv->server_names_size; i++)
433     {
434       BUFFER_APPEND_NUM (ps, priv->server_names[i].type);
435       BUFFER_APPEND_PFX (ps, priv->server_names[i].name,
436                          priv->server_names[i].name_length);
437     }
438   return 0;
439 }
440
441 static int
442 _gnutls_server_name_unpack (gnutls_buffer_st * ps,
443                             extension_priv_data_t * _priv)
444 {
445   server_name_ext_st *priv;
446   int i, ret;
447   extension_priv_data_t epriv;
448
449   priv = gnutls_calloc (1, sizeof (*priv));
450   if (priv == NULL)
451     {
452       gnutls_assert ();
453       return GNUTLS_E_MEMORY_ERROR;
454     }
455
456   BUFFER_POP_NUM (ps, priv->server_names_size);
457   for (i = 0; i < priv->server_names_size; i++)
458     {
459       BUFFER_POP_NUM (ps, priv->server_names[i].type);
460       BUFFER_POP_NUM (ps, priv->server_names[i].name_length);
461       if (priv->server_names[i].name_length >
462           sizeof (priv->server_names[i].name))
463         {
464           gnutls_assert ();
465           return GNUTLS_E_PARSING_ERROR;
466         }
467       BUFFER_POP (ps, priv->server_names[i].name,
468                   priv->server_names[i].name_length);
469     }
470
471   epriv.ptr = priv;
472   *_priv = epriv;
473
474   return 0;
475
476 error:
477   gnutls_free (priv);
478   return ret;
479 }