Add `gnutls/dtls.h' to the distribution.
[gnutls.git] / lib / ext_max_record.c
blob195d37aea3d210c13ed89b056380f8b39b105d30
1 /*
2 * Copyright (C) 2001, 2004, 2005, 2010 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 2.1 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
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA
25 /* This file contains the code for the Max Record Size TLS extension.
28 #include "gnutls_int.h"
29 #include "gnutls_errors.h"
30 #include "gnutls_num.h"
31 #include <gnutls_extensions.h>
32 #include <ext_max_record.h>
34 static int _gnutls_max_record_recv_params (gnutls_session_t session,
35 const opaque * data,
36 size_t data_size);
37 static int _gnutls_max_record_send_params (gnutls_session_t session,
38 gnutls_buffer_st* extdata);
40 static int _gnutls_max_record_unpack (gnutls_buffer_st * ps,
41 extension_priv_data_t * _priv);
42 static int _gnutls_max_record_pack (extension_priv_data_t _priv,
43 gnutls_buffer_st * ps);
45 /* Maps record size to numbers according to the
46 * extensions draft.
48 static int _gnutls_mre_num2record (int num);
49 static int _gnutls_mre_record2num (uint16_t record_size);
52 extension_entry_st ext_mod_max_record_size = {
53 .name = "MAX RECORD SIZE",
54 .type = GNUTLS_EXTENSION_MAX_RECORD_SIZE,
55 .parse_type = GNUTLS_EXT_TLS,
57 .recv_func = _gnutls_max_record_recv_params,
58 .send_func = _gnutls_max_record_send_params,
59 .pack_func = _gnutls_max_record_pack,
60 .unpack_func = _gnutls_max_record_unpack,
61 .deinit_func = NULL
64 /*
65 * In case of a server: if a MAX_RECORD_SIZE extension type is received then it stores
66 * into the session the new value. The server may use gnutls_get_max_record_size(),
67 * in order to access it.
69 * In case of a client: If a different max record size (than the default) has
70 * been specified then it sends the extension.
74 static int
75 _gnutls_max_record_recv_params (gnutls_session_t session,
76 const opaque * data, size_t _data_size)
78 ssize_t new_size;
79 ssize_t data_size = _data_size;
80 extension_priv_data_t epriv;
81 int ret;
83 if (session->security_parameters.entity == GNUTLS_SERVER)
85 if (data_size > 0)
87 DECR_LEN (data_size, 1);
89 new_size = _gnutls_mre_num2record (data[0]);
91 if (new_size < 0)
93 gnutls_assert ();
94 return new_size;
97 session->security_parameters.max_record_send_size = new_size;
98 session->security_parameters.max_record_recv_size = new_size;
101 else
102 { /* CLIENT SIDE - we must check if the sent record size is the right one
104 if (data_size > 0)
106 ret = _gnutls_ext_get_session_data (session,
107 GNUTLS_EXTENSION_MAX_RECORD_SIZE,
108 &epriv);
109 if (ret < 0)
111 gnutls_assert ();
112 return GNUTLS_E_INTERNAL_ERROR;
115 if (data_size != 1)
117 gnutls_assert ();
118 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
121 new_size = _gnutls_mre_num2record (data[0]);
123 if (new_size < 0 || new_size != epriv.num)
125 gnutls_assert ();
126 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
128 else
130 session->security_parameters.max_record_recv_size = epriv.num;
138 return 0;
141 /* returns data_size or a negative number on failure
143 static int
144 _gnutls_max_record_send_params (gnutls_session_t session, gnutls_buffer_st* extdata)
146 uint8_t p;
147 int ret;
149 /* this function sends the client extension data (dnsname) */
150 if (session->security_parameters.entity == GNUTLS_CLIENT)
152 extension_priv_data_t epriv;
154 ret = _gnutls_ext_get_session_data (session,
155 GNUTLS_EXTENSION_MAX_RECORD_SIZE,
156 &epriv);
157 if (ret < 0) /* it is ok not to have it */
159 return 0;
162 if (epriv.num != DEFAULT_MAX_RECORD_SIZE)
164 p = (uint8_t) _gnutls_mre_record2num (epriv.num);
165 ret = _gnutls_buffer_append_data( extdata, &p, 1);
166 if (ret < 0)
167 return gnutls_assert_val(ret);
169 return 1;
173 else
174 { /* server side */
176 if (session->security_parameters.max_record_recv_size !=
177 DEFAULT_MAX_RECORD_SIZE)
180 (uint8_t)
181 _gnutls_mre_record2num
182 (session->security_parameters.max_record_recv_size);
184 ret = _gnutls_buffer_append_data( extdata, &p, 1);
185 if (ret < 0)
186 return gnutls_assert_val(ret);
188 return 1;
192 return 0;
196 static int
197 _gnutls_max_record_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
199 int ret;
201 BUFFER_APPEND_NUM (ps, epriv.num);
203 return 0;
207 static int
208 _gnutls_max_record_unpack (gnutls_buffer_st * ps,
209 extension_priv_data_t * _priv)
211 extension_priv_data_t epriv;
212 int ret;
214 BUFFER_POP_NUM (ps, epriv.num);
216 *_priv = epriv;
218 ret = 0;
219 error:
220 return ret;
224 /* Maps numbers to record sizes according to the
225 * extensions draft.
227 static int
228 _gnutls_mre_num2record (int num)
230 switch (num)
232 case 1:
233 return 512;
234 case 2:
235 return 1024;
236 case 3:
237 return 2048;
238 case 4:
239 return 4096;
240 default:
241 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
245 /* Maps record size to numbers according to the
246 * extensions draft.
248 static int
249 _gnutls_mre_record2num (uint16_t record_size)
251 switch (record_size)
253 case 512:
254 return 1;
255 case 1024:
256 return 2;
257 case 2048:
258 return 3;
259 case 4096:
260 return 4;
261 default:
262 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
268 * gnutls_record_get_max_size:
269 * @session: is a #gnutls_session_t structure.
271 * Get the record size. The maximum record size is negotiated by the
272 * client after the first handshake message.
274 * Returns: The maximum record packet size in this connection.
276 size_t
277 gnutls_record_get_max_size (gnutls_session_t session)
279 /* Recv will hold the negotiated max record size
280 * always.
282 return session->security_parameters.max_record_recv_size;
287 * gnutls_record_set_max_size:
288 * @session: is a #gnutls_session_t structure.
289 * @size: is the new size
291 * This function sets the maximum record packet size in this
292 * connection. This property can only be set to clients. The server
293 * may choose not to accept the requested size.
295 * Acceptable values are 512(=2^9), 1024(=2^10), 2048(=2^11) and
296 * 4096(=2^12). The requested record size does get in effect
297 * immediately only while sending data. The receive part will take
298 * effect after a successful handshake.
300 * This function uses a TLS extension called 'max record size'. Not
301 * all TLS implementations use or even understand this extension.
303 * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
304 * otherwise an error code is returned.
306 ssize_t
307 gnutls_record_set_max_size (gnutls_session_t session, size_t size)
309 ssize_t new_size;
310 extension_priv_data_t epriv;
312 if (session->security_parameters.entity == GNUTLS_SERVER)
313 return GNUTLS_E_INVALID_REQUEST;
315 new_size = _gnutls_mre_record2num (size);
317 if (new_size < 0)
319 gnutls_assert ();
320 return new_size;
323 session->security_parameters.max_record_send_size = size;
324 epriv.num = size;
326 _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_MAX_RECORD_SIZE,
327 epriv);
329 return 0;