2 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include "gnutls_int.h"
24 #include "gnutls_auth.h"
25 #include "gnutls_errors.h"
26 #include "gnutls_num.h"
27 #include <ext/server_name.h>
29 static int _gnutls_server_name_recv_params (gnutls_session_t session
,
32 static int _gnutls_server_name_send_params (gnutls_session_t session
,
33 gnutls_buffer_st
* extdata
);
35 static int _gnutls_server_name_unpack (gnutls_buffer_st
* ps
,
36 extension_priv_data_t
* _priv
);
37 static int _gnutls_server_name_pack (extension_priv_data_t _priv
,
38 gnutls_buffer_st
* ps
);
39 static void _gnutls_server_name_deinit_data (extension_priv_data_t priv
);
42 extension_entry_st ext_mod_server_name
= {
43 .name
= "SERVER NAME",
44 .type
= GNUTLS_EXTENSION_SERVER_NAME
,
45 .parse_type
= GNUTLS_EXT_APPLICATION
,
47 .recv_func
= _gnutls_server_name_recv_params
,
48 .send_func
= _gnutls_server_name_send_params
,
49 .pack_func
= _gnutls_server_name_pack
,
50 .unpack_func
= _gnutls_server_name_unpack
,
51 .deinit_func
= _gnutls_server_name_deinit_data
,
55 * In case of a server: if a NAME_DNS extension type is received then
56 * it stores into the session the value of NAME_DNS. The server may
57 * use gnutls_ext_get_server_name(), in order to access it.
59 * In case of a client: If a proper NAME_DNS extension type is found
60 * in the session then it sends the extension to the peer.
64 _gnutls_server_name_recv_params (gnutls_session_t session
,
65 const uint8_t * data
, size_t _data_size
)
68 const unsigned char *p
;
70 ssize_t data_size
= _data_size
;
72 server_name_ext_st
*priv
;
73 extension_priv_data_t epriv
;
75 if (session
->security_parameters
.entity
== GNUTLS_SERVER
)
77 DECR_LENGTH_RET (data_size
, 2, 0);
78 len
= _gnutls_read_uint16 (data
);
82 /* This is unexpected packet length, but
83 * just ignore it, for now.
91 /* Count all server_names in the packet. */
94 DECR_LENGTH_RET (data_size
, 1, 0);
97 DECR_LEN (data_size
, 2);
98 len
= _gnutls_read_uint16 (p
);
103 DECR_LENGTH_RET (data_size
, len
, 0);
108 _gnutls_handshake_log
109 ("HSK[%p]: Received (0) size server name (under attack?)\n",
114 /* we cannot accept more server names.
116 if (server_names
> MAX_SERVER_NAME_EXTENSIONS
)
118 _gnutls_handshake_log
119 ("HSK[%p]: Too many server names received (under attack?)\n",
121 server_names
= MAX_SERVER_NAME_EXTENSIONS
;
124 if (server_names
== 0)
125 return 0; /* no names found */
127 priv
= gnutls_calloc (1, sizeof (*priv
));
131 return GNUTLS_E_MEMORY_ERROR
;
134 priv
->server_names_size
= server_names
;
137 for (i
= 0; i
< server_names
; i
++)
142 len
= _gnutls_read_uint16 (p
);
147 case 0: /* NAME_DNS */
148 if (len
<= MAX_SERVER_NAME_SIZE
)
150 memcpy (priv
->server_names
[i
].name
, p
, len
);
151 priv
->server_names
[i
].name_length
= len
;
152 priv
->server_names
[i
].type
= GNUTLS_NAME_DNS
;
157 /* move to next record */
162 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SERVER_NAME
,
170 /* returns data_size or a negative number on failure
173 _gnutls_server_name_send_params (gnutls_session_t session
,
174 gnutls_buffer_st
* extdata
)
178 int total_size
= 0, ret
;
179 server_name_ext_st
*priv
;
180 extension_priv_data_t epriv
;
183 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SERVER_NAME
,
189 /* this function sends the client extension data (dnsname)
191 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
195 if (priv
->server_names_size
== 0)
201 for (i
= 0; i
< priv
->server_names_size
; i
++)
203 /* count the total size
205 len
= priv
->server_names
[i
].name_length
;
207 /* uint8_t + uint16_t + size
209 total_size
+= 1 + 2 + len
;
212 /* UINT16: write total size of all names
214 ret
= _gnutls_buffer_append_prefix(extdata
, 16, total_size
- 2);
216 return gnutls_assert_val(ret
);
218 for (i
= 0; i
< priv
->server_names_size
; i
++)
221 switch (priv
->server_names
[i
].type
)
223 case GNUTLS_NAME_DNS
:
224 len
= priv
->server_names
[i
].name_length
;
228 /* UINT8: type of this extension
229 * UINT16: size of the first name
230 * LEN: the actual server name.
232 ret
= _gnutls_buffer_append_prefix(extdata
, 8, 0);
234 return gnutls_assert_val(ret
);
236 ret
= _gnutls_buffer_append_data_prefix(extdata
, 16, priv
->server_names
[i
].name
, len
);
238 return gnutls_assert_val(ret
);
243 return GNUTLS_E_INTERNAL_ERROR
;
252 * gnutls_server_name_get:
253 * @session: is a #gnutls_session_t structure.
254 * @data: will hold the data
255 * @data_length: will hold the data length. Must hold the maximum size of data.
256 * @type: will hold the server name indicator type
257 * @indx: is the index of the server_name
259 * This function will allow you to get the name indication (if any), a
260 * client has sent. The name indication may be any of the enumeration
261 * gnutls_server_name_type_t.
263 * If @type is GNUTLS_NAME_DNS, then this function is to be used by
264 * servers that support virtual hosting, and the data will be a null
265 * terminated UTF-8 string.
267 * If @data has not enough size to hold the server name
268 * GNUTLS_E_SHORT_MEMORY_BUFFER is returned, and @data_length will
269 * hold the required size.
271 * @index is used to retrieve more than one server names (if sent by
272 * the client). The first server name has an index of 0, the second 1
273 * and so on. If no name with the given index exists
274 * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
276 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
277 * otherwise a negative error code is returned.
280 gnutls_server_name_get (gnutls_session_t session
, void *data
,
281 size_t * data_length
,
282 unsigned int *type
, unsigned int indx
)
285 server_name_ext_st
*priv
;
287 extension_priv_data_t epriv
;
289 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
292 return GNUTLS_E_INVALID_REQUEST
;
296 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SERVER_NAME
,
301 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
306 if (indx
+ 1 > priv
->server_names_size
)
308 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
311 *type
= priv
->server_names
[indx
].type
;
313 if (*data_length
> /* greater since we need one extra byte for the null */
314 priv
->server_names
[indx
].name_length
)
316 *data_length
= priv
->server_names
[indx
].name_length
;
317 memcpy (data
, priv
->server_names
[indx
].name
, *data_length
);
319 if (*type
== GNUTLS_NAME_DNS
) /* null terminate */
320 _data
[(*data_length
)] = 0;
325 *data_length
= priv
->server_names
[indx
].name_length
;
326 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
333 * gnutls_server_name_set:
334 * @session: is a #gnutls_session_t structure.
335 * @type: specifies the indicator type
336 * @name: is a string that contains the server name.
337 * @name_length: holds the length of name
339 * This function is to be used by clients that want to inform (via a
340 * TLS extension mechanism) the server of the name they connected to.
341 * This should be used by clients that connect to servers that do
344 * The value of @name depends on the @type type. In case of
345 * %GNUTLS_NAME_DNS, an ASCII (0)-terminated domain name string,
346 * without the trailing dot, is expected. IPv4 or IPv6 addresses are
349 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
350 * otherwise a negative error code is returned.
353 gnutls_server_name_set (gnutls_session_t session
,
354 gnutls_server_name_type_t type
,
355 const void *name
, size_t name_length
)
357 int server_names
, ret
;
358 server_name_ext_st
*priv
;
359 extension_priv_data_t epriv
;
362 if (session
->security_parameters
.entity
== GNUTLS_SERVER
)
365 return GNUTLS_E_INVALID_REQUEST
;
368 if (name_length
> MAX_SERVER_NAME_SIZE
)
369 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
372 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SERVER_NAME
,
381 priv
= gnutls_calloc (1, sizeof (*priv
));
385 return GNUTLS_E_MEMORY_ERROR
;
392 server_names
= priv
->server_names_size
+ 1;
394 if (server_names
> MAX_SERVER_NAME_EXTENSIONS
)
395 server_names
= MAX_SERVER_NAME_EXTENSIONS
;
397 priv
->server_names
[server_names
- 1].type
= type
;
398 memcpy (priv
->server_names
[server_names
- 1].name
, name
, name_length
);
399 priv
->server_names
[server_names
- 1].name_length
= name_length
;
401 priv
->server_names_size
++;
404 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SERVER_NAME
,
411 _gnutls_server_name_deinit_data (extension_priv_data_t priv
)
413 gnutls_free (priv
.ptr
);
417 _gnutls_server_name_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
419 server_name_ext_st
*priv
= epriv
.ptr
;
423 BUFFER_APPEND_NUM (ps
, priv
->server_names_size
);
424 for (i
= 0; i
< priv
->server_names_size
; i
++)
426 BUFFER_APPEND_NUM (ps
, priv
->server_names
[i
].type
);
427 BUFFER_APPEND_PFX4 (ps
, priv
->server_names
[i
].name
,
428 priv
->server_names
[i
].name_length
);
434 _gnutls_server_name_unpack (gnutls_buffer_st
* ps
,
435 extension_priv_data_t
* _priv
)
437 server_name_ext_st
*priv
;
440 extension_priv_data_t epriv
;
442 priv
= gnutls_calloc (1, sizeof (*priv
));
446 return GNUTLS_E_MEMORY_ERROR
;
449 BUFFER_POP_NUM (ps
, priv
->server_names_size
);
450 for (i
= 0; i
< priv
->server_names_size
; i
++)
452 BUFFER_POP_NUM (ps
, priv
->server_names
[i
].type
);
453 BUFFER_POP_NUM (ps
, priv
->server_names
[i
].name_length
);
454 if (priv
->server_names
[i
].name_length
>
455 sizeof (priv
->server_names
[i
].name
))
458 return GNUTLS_E_PARSING_ERROR
;
460 BUFFER_POP (ps
, priv
->server_names
[i
].name
,
461 priv
->server_names
[i
].name_length
);