Line data Source code
1 : /*
2 : * Copyright (C) 2007-2012 Free Software Foundation, Inc.
3 : *
4 : * Author: Simon Josefsson
5 : *
6 : * This file is part of GnuTLS.
7 : *
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.
12 : *
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.
17 : *
18 : * You should have received a copy of the GNU Lesser General Public License
19 : * along with this program. If not, see <https://www.gnu.org/licenses/>
20 : *
21 : */
22 :
23 : /* This file contains support functions for 'TLS Handshake Message for
24 : * Supplemental Data' (RFC 4680).
25 : *
26 : * The idea here is simple. gnutls_handshake() in gnuts_handshake.c
27 : * will call _gnutls_gen_supplemental and _gnutls_parse_supplemental
28 : * when some extension requested that supplemental data be sent or
29 : * received. Extension request this by setting the flags
30 : * do_recv_supplemental or do_send_supplemental in the session.
31 : *
32 : * The functions in this file iterate through the _gnutls_supplemental
33 : * array, and calls the send/recv functions for each respective data
34 : * type.
35 : *
36 : * The receive function of each data type is responsible for decoding
37 : * its own data. If the extension did not expect to receive
38 : * supplemental data, it should return GNUTLS_E_UNEXPECTED_PACKET.
39 : * Otherwise, it just parse the data as normal.
40 : *
41 : * The send function needs to append the 2-byte data format type, and
42 : * append the 2-byte length of its data, and the data. If it doesn't
43 : * want to send any data, it is fine to return without doing anything.
44 : */
45 :
46 : #include "gnutls_int.h"
47 : #include <gnutls/gnutls.h>
48 : #include "supplemental.h"
49 : #include "errors.h"
50 : #include "num.h"
51 :
52 : typedef struct gnutls_supplemental_entry_st {
53 : char *name;
54 : gnutls_supplemental_data_format_type_t type;
55 : gnutls_supp_recv_func supp_recv_func;
56 : gnutls_supp_send_func supp_send_func;
57 : } gnutls_supplemental_entry_st;
58 :
59 : static size_t suppfunc_size = 0;
60 : static gnutls_supplemental_entry_st *suppfunc = NULL;
61 :
62 : /**
63 : * gnutls_supplemental_get_name:
64 : * @type: is a supplemental data format type
65 : *
66 : * Convert a #gnutls_supplemental_data_format_type_t value to a
67 : * string.
68 : *
69 : * Returns: a string that contains the name of the specified
70 : * supplemental data format type, or %NULL for unknown types.
71 : **/
72 : const char
73 0 : *gnutls_supplemental_get_name(gnutls_supplemental_data_format_type_t
74 : type)
75 : {
76 0 : size_t i;
77 :
78 0 : for (i = 0; i < suppfunc_size; i++) {
79 0 : if (suppfunc[i].type == type)
80 0 : return suppfunc[i].name;
81 : }
82 :
83 : return NULL;
84 : }
85 :
86 2200 : void _gnutls_supplemental_deinit(void)
87 : {
88 2200 : unsigned i;
89 :
90 2218 : for (i = 0; i < suppfunc_size; i++) {
91 18 : gnutls_free(suppfunc[i].name);
92 : }
93 2200 : gnutls_free(suppfunc);
94 :
95 2200 : suppfunc = NULL;
96 2200 : suppfunc_size = 0;
97 2200 : }
98 :
99 : static gnutls_supp_recv_func
100 30 : get_supp_func_recv(gnutls_session_t session, gnutls_supplemental_data_format_type_t type)
101 : {
102 30 : size_t i;
103 :
104 30 : for (i = 0; i < session->internals.rsup_size; i++) {
105 15 : if (session->internals.rsup[i].type == type)
106 15 : return session->internals.rsup[i].supp_recv_func;
107 : }
108 :
109 15 : for (i = 0; i < suppfunc_size; i++) {
110 15 : if (suppfunc[i].type == type)
111 15 : return suppfunc[i].supp_recv_func;
112 : }
113 :
114 : return NULL;
115 : }
116 :
117 30 : static int gen_supplemental(gnutls_session_t session, const gnutls_supplemental_entry_st *supp,
118 : gnutls_buffer_st * buf)
119 : {
120 30 : int ret;
121 30 : gnutls_supp_send_func supp_send = supp->supp_send_func;
122 30 : size_t sizepos = buf->length;
123 :
124 : /* Make room for supplement type and length byte length field. */
125 30 : ret = _gnutls_buffer_append_data(buf, "\0\0\0\0", 4);
126 30 : if (ret < 0) {
127 0 : gnutls_assert();
128 0 : return ret;
129 : }
130 :
131 30 : ret = supp_send(session, buf);
132 30 : if (ret < 0) {
133 0 : gnutls_assert();
134 0 : return ret;
135 : }
136 :
137 : /* If data were added, store type+length, otherwise reset. */
138 30 : if (buf->length > sizepos + 4) {
139 30 : buf->data[sizepos] = (supp->type >> 8) & 0xFF;
140 30 : buf->data[sizepos + 1] = supp->type & 0xFF;
141 30 : buf->data[sizepos + 2] =
142 30 : ((buf->length - sizepos - 4) >> 8) & 0xFF;
143 30 : buf->data[sizepos + 3] =
144 30 : (buf->length - sizepos - 4) & 0xFF;
145 : } else
146 0 : buf->length -= 4;
147 :
148 : return 0;
149 : }
150 :
151 : int
152 30 : _gnutls_gen_supplemental(gnutls_session_t session, gnutls_buffer_st * buf)
153 : {
154 30 : size_t i;
155 30 : int ret;
156 30 : unsigned init_pos = buf->length;
157 :
158 : /* Make room for 3 byte length field. */
159 30 : ret = _gnutls_buffer_append_data(buf, "\0\0\0", 3);
160 30 : if (ret < 0) {
161 0 : gnutls_assert();
162 0 : return ret;
163 : }
164 :
165 45 : for (i = 0; i < session->internals.rsup_size; i++) {
166 15 : ret = gen_supplemental(session, &session->internals.rsup[i], buf);
167 15 : if (ret < 0)
168 0 : return gnutls_assert_val(ret);
169 : }
170 :
171 45 : for (i = 0; i < suppfunc_size; i++) {
172 15 : ret = gen_supplemental(session, &suppfunc[i], buf);
173 15 : if (ret < 0)
174 0 : return gnutls_assert_val(ret);
175 : }
176 :
177 30 : i = buf->length - init_pos - 3;
178 :
179 30 : buf->data[init_pos] = (i >> 16) & 0xFF;
180 30 : buf->data[init_pos+1] = (i >> 8) & 0xFF;
181 30 : buf->data[init_pos+2] = i & 0xFF;
182 :
183 30 : _gnutls_debug_log
184 : ("EXT[%p]: Sending %d bytes of supplemental data\n", session,
185 : (int) buf->length);
186 :
187 30 : return buf->length - init_pos;
188 : }
189 :
190 : int
191 30 : _gnutls_parse_supplemental(gnutls_session_t session,
192 : const uint8_t * data, int datalen)
193 : {
194 30 : const uint8_t *p = data;
195 30 : size_t dsize = datalen;
196 30 : size_t total_size;
197 :
198 30 : DECR_LEN(dsize, 3);
199 30 : total_size = _gnutls_read_uint24(p);
200 30 : p += 3;
201 :
202 30 : if (dsize != total_size) {
203 0 : gnutls_assert();
204 0 : return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
205 : }
206 :
207 30 : do {
208 30 : uint16_t supp_data_type;
209 30 : uint16_t supp_data_length;
210 30 : gnutls_supp_recv_func recv_func;
211 :
212 30 : DECR_LEN(dsize, 2);
213 30 : supp_data_type = _gnutls_read_uint16(p);
214 30 : p += 2;
215 :
216 30 : DECR_LEN(dsize, 2);
217 30 : supp_data_length = _gnutls_read_uint16(p);
218 30 : p += 2;
219 :
220 30 : _gnutls_debug_log
221 : ("EXT[%p]: Got supplemental type=%02x length=%d\n",
222 : session, supp_data_type, supp_data_length);
223 :
224 30 : recv_func = get_supp_func_recv(session, supp_data_type);
225 30 : if (recv_func) {
226 30 : int ret = recv_func(session, p, supp_data_length);
227 30 : if (ret < 0) {
228 0 : gnutls_assert();
229 0 : return ret;
230 : }
231 : } else {
232 0 : gnutls_assert();
233 0 : return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
234 : }
235 :
236 30 : DECR_LEN(dsize, supp_data_length);
237 30 : p += supp_data_length;
238 : }
239 30 : while (dsize > 0);
240 :
241 : return 0;
242 : }
243 :
244 : static int
245 18 : _gnutls_supplemental_register(gnutls_supplemental_entry_st *entry)
246 : {
247 18 : gnutls_supplemental_entry_st *p;
248 18 : unsigned i;
249 :
250 18 : for (i = 0; i < suppfunc_size; i++) {
251 0 : if (entry->type == suppfunc[i].type)
252 0 : return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
253 : }
254 :
255 36 : p = gnutls_realloc_fast(suppfunc,
256 18 : sizeof(*suppfunc) * (suppfunc_size + 1));
257 18 : if (!p) {
258 0 : gnutls_assert();
259 0 : return GNUTLS_E_MEMORY_ERROR;
260 : }
261 :
262 18 : suppfunc = p;
263 :
264 18 : memcpy(&suppfunc[suppfunc_size], entry, sizeof(*entry));
265 :
266 18 : suppfunc_size++;
267 :
268 18 : return GNUTLS_E_SUCCESS;
269 : }
270 :
271 : /**
272 : * gnutls_supplemental_register:
273 : * @name: the name of the supplemental data to register
274 : * @type: the type of the supplemental data format
275 : * @recv_func: the function to receive the data
276 : * @send_func: the function to send the data
277 : *
278 : * This function will register a new supplemental data type (rfc4680).
279 : * The registered data will remain until gnutls_global_deinit()
280 : * is called. The provided @type must be an unassigned type in
281 : * %gnutls_supplemental_data_format_type_t. If the type is already
282 : * registered or handled by GnuTLS internally %GNUTLS_E_ALREADY_REGISTERED
283 : * will be returned.
284 : *
285 : * This function is not thread safe. As supplemental data are not defined under
286 : * TLS 1.3, this function will disable TLS 1.3 support globally.
287 : *
288 : * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
289 : *
290 : * Since: 3.4.0
291 : **/
292 : int
293 18 : gnutls_supplemental_register(const char *name, gnutls_supplemental_data_format_type_t type,
294 : gnutls_supp_recv_func recv_func, gnutls_supp_send_func send_func)
295 : {
296 18 : gnutls_supplemental_entry_st tmp_entry;
297 18 : int ret;
298 :
299 18 : tmp_entry.name = gnutls_strdup(name);
300 18 : tmp_entry.type = type;
301 18 : tmp_entry.supp_recv_func = recv_func;
302 18 : tmp_entry.supp_send_func = send_func;
303 :
304 18 : ret = _gnutls_supplemental_register(&tmp_entry);
305 18 : if (ret < 0) {
306 0 : gnutls_free(tmp_entry.name);
307 : }
308 :
309 18 : _gnutls_disable_tls13 = 1;
310 :
311 18 : return ret;
312 : }
313 :
314 : /**
315 : * gnutls_session_supplemental_register:
316 : * @session: the session for which this will be registered
317 : * @name: the name of the supplemental data to register
318 : * @type: the type of the supplemental data format
319 : * @recv_func: the function to receive the data
320 : * @send_func: the function to send the data
321 : * @flags: must be zero
322 : *
323 : * This function will register a new supplemental data type (rfc4680).
324 : * The registered supplemental functions will be used for that specific
325 : * session. The provided @type must be an unassigned type in
326 : * %gnutls_supplemental_data_format_type_t.
327 : *
328 : * If the type is already registered or handled by GnuTLS internally
329 : * %GNUTLS_E_ALREADY_REGISTERED will be returned.
330 : *
331 : * As supplemental data are not defined under TLS 1.3, this function will
332 : * disable TLS 1.3 support for the given session.
333 : *
334 : * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
335 : *
336 : * Since: 3.5.5
337 : **/
338 : int
339 18 : gnutls_session_supplemental_register(gnutls_session_t session, const char *name,
340 : gnutls_supplemental_data_format_type_t type,
341 : gnutls_supp_recv_func recv_func,
342 : gnutls_supp_send_func send_func,
343 : unsigned flags)
344 : {
345 18 : gnutls_supplemental_entry_st tmp_entry;
346 18 : gnutls_supplemental_entry_st *p;
347 18 : unsigned i;
348 :
349 18 : tmp_entry.name = NULL;
350 18 : tmp_entry.type = type;
351 18 : tmp_entry.supp_recv_func = recv_func;
352 18 : tmp_entry.supp_send_func = send_func;
353 :
354 18 : for (i = 0; i < suppfunc_size; i++) {
355 0 : if (type == suppfunc[i].type)
356 0 : return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
357 : }
358 :
359 36 : p = gnutls_realloc(session->internals.rsup,
360 18 : sizeof(gnutls_supplemental_entry_st)*(session->internals.rsup_size + 1));
361 18 : if (!p)
362 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
363 :
364 18 : session->internals.rsup = p;
365 :
366 18 : memcpy(&session->internals.rsup[session->internals.rsup_size], &tmp_entry, sizeof(tmp_entry));
367 18 : session->internals.rsup_size++;
368 :
369 18 : session->internals.flags |= INT_FLAG_NO_TLS13;
370 :
371 18 : return GNUTLS_E_SUCCESS;
372 : }
373 :
374 : /**
375 : * gnutls_supplemental_recv:
376 : * @session: is a #gnutls_session_t type.
377 : * @do_recv_supplemental: non-zero in order to expect supplemental data
378 : *
379 : * This function is to be called by an extension handler to
380 : * instruct gnutls to attempt to receive supplemental data
381 : * during the handshake process.
382 : *
383 : * Since: 3.4.0
384 : **/
385 : void
386 30 : gnutls_supplemental_recv(gnutls_session_t session, unsigned do_recv_supplemental)
387 : {
388 30 : session->security_parameters.do_recv_supplemental = do_recv_supplemental;
389 30 : }
390 :
391 : /**
392 : * gnutls_supplemental_send:
393 : * @session: is a #gnutls_session_t type.
394 : * @do_send_supplemental: non-zero in order to send supplemental data
395 : *
396 : * This function is to be called by an extension handler to
397 : * instruct gnutls to send supplemental data during the handshake process.
398 : *
399 : * Since: 3.4.0
400 : **/
401 : void
402 30 : gnutls_supplemental_send(gnutls_session_t session, unsigned do_send_supplemental)
403 : {
404 30 : session->security_parameters.do_send_supplemental = do_send_supplemental;
405 30 : }
|