/src/gnutls/lib/supplemental.c
Line  | Count  | Source (jump to first uncovered line)  | 
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  |  | #include "intprops.h"  | 
52  |  |  | 
53  |  | typedef struct gnutls_supplemental_entry_st { | 
54  |  |   char *name;  | 
55  |  |   gnutls_supplemental_data_format_type_t type;  | 
56  |  |   gnutls_supp_recv_func supp_recv_func;  | 
57  |  |   gnutls_supp_send_func supp_send_func;  | 
58  |  | } gnutls_supplemental_entry_st;  | 
59  |  |  | 
60  |  | static size_t suppfunc_size = 0;  | 
61  |  | static gnutls_supplemental_entry_st *suppfunc = NULL;  | 
62  |  |  | 
63  |  | /**  | 
64  |  |  * gnutls_supplemental_get_name:  | 
65  |  |  * @type: is a supplemental data format type  | 
66  |  |  *  | 
67  |  |  * Convert a #gnutls_supplemental_data_format_type_t value to a  | 
68  |  |  * string.  | 
69  |  |  *  | 
70  |  |  * Returns: a string that contains the name of the specified  | 
71  |  |  *   supplemental data format type, or %NULL for unknown types.  | 
72  |  |  **/  | 
73  |  | const char *  | 
74  |  | gnutls_supplemental_get_name(gnutls_supplemental_data_format_type_t type)  | 
75  | 0  | { | 
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  | 0  |   }  | 
82  |  |  | 
83  | 0  |   return NULL;  | 
84  | 0  | }  | 
85  |  |  | 
86  |  | void _gnutls_supplemental_deinit(void)  | 
87  | 0  | { | 
88  | 0  |   unsigned i;  | 
89  |  | 
  | 
90  | 0  |   for (i = 0; i < suppfunc_size; i++) { | 
91  | 0  |     gnutls_free(suppfunc[i].name);  | 
92  | 0  |   }  | 
93  | 0  |   gnutls_free(suppfunc);  | 
94  |  | 
  | 
95  | 0  |   suppfunc = NULL;  | 
96  | 0  |   suppfunc_size = 0;  | 
97  | 0  | }  | 
98  |  |  | 
99  |  | static gnutls_supp_recv_func  | 
100  |  | get_supp_func_recv(gnutls_session_t session,  | 
101  |  |        gnutls_supplemental_data_format_type_t type)  | 
102  | 0  | { | 
103  | 0  |   size_t i;  | 
104  |  | 
  | 
105  | 0  |   for (i = 0; i < session->internals.rsup_size; i++) { | 
106  | 0  |     if (session->internals.rsup[i].type == type)  | 
107  | 0  |       return session->internals.rsup[i].supp_recv_func;  | 
108  | 0  |   }  | 
109  |  |  | 
110  | 0  |   for (i = 0; i < suppfunc_size; i++) { | 
111  | 0  |     if (suppfunc[i].type == type)  | 
112  | 0  |       return suppfunc[i].supp_recv_func;  | 
113  | 0  |   }  | 
114  |  |  | 
115  | 0  |   return NULL;  | 
116  | 0  | }  | 
117  |  |  | 
118  |  | static int gen_supplemental(gnutls_session_t session,  | 
119  |  |           const gnutls_supplemental_entry_st *supp,  | 
120  |  |           gnutls_buffer_st *buf)  | 
121  | 0  | { | 
122  | 0  |   int ret;  | 
123  | 0  |   gnutls_supp_send_func supp_send = supp->supp_send_func;  | 
124  | 0  |   size_t sizepos = buf->length;  | 
125  |  |  | 
126  |  |   /* Make room for supplement type and length byte length field. */  | 
127  | 0  |   ret = _gnutls_buffer_append_data(buf, "\0\0\0\0", 4);  | 
128  | 0  |   if (ret < 0) { | 
129  | 0  |     gnutls_assert();  | 
130  | 0  |     return ret;  | 
131  | 0  |   }  | 
132  |  |  | 
133  | 0  |   ret = supp_send(session, buf);  | 
134  | 0  |   if (ret < 0) { | 
135  | 0  |     gnutls_assert();  | 
136  | 0  |     return ret;  | 
137  | 0  |   }  | 
138  |  |  | 
139  |  |   /* If data were added, store type+length, otherwise reset. */  | 
140  | 0  |   if (buf->length > sizepos + 4) { | 
141  | 0  |     buf->data[sizepos] = (supp->type >> 8) & 0xFF;  | 
142  | 0  |     buf->data[sizepos + 1] = supp->type & 0xFF;  | 
143  | 0  |     buf->data[sizepos + 2] = ((buf->length - sizepos - 4) >> 8) &  | 
144  | 0  |            0xFF;  | 
145  | 0  |     buf->data[sizepos + 3] = (buf->length - sizepos - 4) & 0xFF;  | 
146  | 0  |   } else  | 
147  | 0  |     buf->length -= 4;  | 
148  |  | 
  | 
149  | 0  |   return 0;  | 
150  | 0  | }  | 
151  |  |  | 
152  |  | int _gnutls_gen_supplemental(gnutls_session_t session, gnutls_buffer_st *buf)  | 
153  | 0  | { | 
154  | 0  |   size_t i;  | 
155  | 0  |   int ret;  | 
156  | 0  |   unsigned init_pos = buf->length;  | 
157  |  |  | 
158  |  |   /* Make room for 3 byte length field. */  | 
159  | 0  |   ret = _gnutls_buffer_append_data(buf, "\0\0\0", 3);  | 
160  | 0  |   if (ret < 0) { | 
161  | 0  |     gnutls_assert();  | 
162  | 0  |     return ret;  | 
163  | 0  |   }  | 
164  |  |  | 
165  | 0  |   for (i = 0; i < session->internals.rsup_size; i++) { | 
166  | 0  |     ret = gen_supplemental(session, &session->internals.rsup[i],  | 
167  | 0  |                buf);  | 
168  | 0  |     if (ret < 0)  | 
169  | 0  |       return gnutls_assert_val(ret);  | 
170  | 0  |   }  | 
171  |  |  | 
172  | 0  |   for (i = 0; i < suppfunc_size; i++) { | 
173  | 0  |     ret = gen_supplemental(session, &suppfunc[i], buf);  | 
174  | 0  |     if (ret < 0)  | 
175  | 0  |       return gnutls_assert_val(ret);  | 
176  | 0  |   }  | 
177  |  |  | 
178  | 0  |   i = buf->length - init_pos - 3;  | 
179  |  | 
  | 
180  | 0  |   buf->data[init_pos] = (i >> 16) & 0xFF;  | 
181  | 0  |   buf->data[init_pos + 1] = (i >> 8) & 0xFF;  | 
182  | 0  |   buf->data[init_pos + 2] = i & 0xFF;  | 
183  |  | 
  | 
184  | 0  |   _gnutls_debug_log("EXT[%p]: Sending %d bytes of supplemental data\n", | 
185  | 0  |         session, (int)buf->length);  | 
186  |  | 
  | 
187  | 0  |   return buf->length - init_pos;  | 
188  | 0  | }  | 
189  |  |  | 
190  |  | int _gnutls_parse_supplemental(gnutls_session_t session, const uint8_t *data,  | 
191  |  |              int datalen)  | 
192  | 0  | { | 
193  | 0  |   const uint8_t *p = data;  | 
194  | 0  |   size_t dsize = datalen;  | 
195  | 0  |   size_t total_size;  | 
196  |  | 
  | 
197  | 0  |   DECR_LEN(dsize, 3);  | 
198  | 0  |   total_size = _gnutls_read_uint24(p);  | 
199  | 0  |   p += 3;  | 
200  |  | 
  | 
201  | 0  |   if (dsize != total_size) { | 
202  | 0  |     gnutls_assert();  | 
203  | 0  |     return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;  | 
204  | 0  |   }  | 
205  |  |  | 
206  | 0  |   do { | 
207  | 0  |     uint16_t supp_data_type;  | 
208  | 0  |     uint16_t supp_data_length;  | 
209  | 0  |     gnutls_supp_recv_func recv_func;  | 
210  |  | 
  | 
211  | 0  |     DECR_LEN(dsize, 2);  | 
212  | 0  |     supp_data_type = _gnutls_read_uint16(p);  | 
213  | 0  |     p += 2;  | 
214  |  | 
  | 
215  | 0  |     DECR_LEN(dsize, 2);  | 
216  | 0  |     supp_data_length = _gnutls_read_uint16(p);  | 
217  | 0  |     p += 2;  | 
218  |  | 
  | 
219  | 0  |     _gnutls_debug_log(  | 
220  | 0  |       "EXT[%p]: Got supplemental type=%02x length=%d\n",  | 
221  | 0  |       session, supp_data_type, supp_data_length);  | 
222  |  | 
  | 
223  | 0  |     recv_func = get_supp_func_recv(session, supp_data_type);  | 
224  | 0  |     if (recv_func) { | 
225  | 0  |       int ret = recv_func(session, p, supp_data_length);  | 
226  | 0  |       if (ret < 0) { | 
227  | 0  |         gnutls_assert();  | 
228  | 0  |         return ret;  | 
229  | 0  |       }  | 
230  | 0  |     } else { | 
231  | 0  |       gnutls_assert();  | 
232  | 0  |       return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;  | 
233  | 0  |     }  | 
234  |  |  | 
235  | 0  |     DECR_LEN(dsize, supp_data_length);  | 
236  | 0  |     p += supp_data_length;  | 
237  | 0  |   } while (dsize > 0);  | 
238  |  |  | 
239  | 0  |   return 0;  | 
240  | 0  | }  | 
241  |  |  | 
242  |  | static int _gnutls_supplemental_register(gnutls_supplemental_entry_st *entry)  | 
243  | 0  | { | 
244  | 0  |   gnutls_supplemental_entry_st *p;  | 
245  | 0  |   unsigned i;  | 
246  |  | 
  | 
247  | 0  |   for (i = 0; i < suppfunc_size; i++) { | 
248  | 0  |     if (entry->type == suppfunc[i].type)  | 
249  | 0  |       return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);  | 
250  | 0  |   }  | 
251  |  |  | 
252  | 0  |   if (unlikely(INT_ADD_OVERFLOW(suppfunc_size, 1))) { | 
253  | 0  |     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);  | 
254  | 0  |   }  | 
255  |  |  | 
256  | 0  |   p = _gnutls_reallocarray_fast(suppfunc, suppfunc_size + 1,  | 
257  | 0  |               sizeof(*suppfunc));  | 
258  | 0  |   if (!p) { | 
259  | 0  |     gnutls_assert();  | 
260  | 0  |     return GNUTLS_E_MEMORY_ERROR;  | 
261  | 0  |   }  | 
262  |  |  | 
263  | 0  |   suppfunc = p;  | 
264  |  | 
  | 
265  | 0  |   memcpy(&suppfunc[suppfunc_size], entry, sizeof(*entry));  | 
266  |  | 
  | 
267  | 0  |   suppfunc_size++;  | 
268  |  | 
  | 
269  | 0  |   return GNUTLS_E_SUCCESS;  | 
270  | 0  | }  | 
271  |  |  | 
272  |  | /**  | 
273  |  |  * gnutls_supplemental_register:  | 
274  |  |  * @name: the name of the supplemental data to register  | 
275  |  |  * @type: the type of the supplemental data format  | 
276  |  |  * @recv_func: the function to receive the data  | 
277  |  |  * @send_func: the function to send the data  | 
278  |  |  *  | 
279  |  |  * This function will register a new supplemental data type (rfc4680).  | 
280  |  |  * The registered data will remain until gnutls_global_deinit()  | 
281  |  |  * is called. The provided @type must be an unassigned type in  | 
282  |  |  * %gnutls_supplemental_data_format_type_t. If the type is already  | 
283  |  |  * registered or handled by GnuTLS internally %GNUTLS_E_ALREADY_REGISTERED  | 
284  |  |  * will be returned.  | 
285  |  |  *  | 
286  |  |  * This function is not thread safe. As supplemental data are not defined under  | 
287  |  |  * TLS 1.3, this function will disable TLS 1.3 support globally.  | 
288  |  |  *  | 
289  |  |  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.  | 
290  |  |  *  | 
291  |  |  * Since: 3.4.0  | 
292  |  |  **/  | 
293  |  | int gnutls_supplemental_register(const char *name,  | 
294  |  |          gnutls_supplemental_data_format_type_t type,  | 
295  |  |          gnutls_supp_recv_func recv_func,  | 
296  |  |          gnutls_supp_send_func send_func)  | 
297  | 0  | { | 
298  | 0  |   gnutls_supplemental_entry_st tmp_entry;  | 
299  | 0  |   int ret;  | 
300  |  | 
  | 
301  | 0  |   tmp_entry.name = gnutls_strdup(name);  | 
302  | 0  |   tmp_entry.type = type;  | 
303  | 0  |   tmp_entry.supp_recv_func = recv_func;  | 
304  | 0  |   tmp_entry.supp_send_func = send_func;  | 
305  |  | 
  | 
306  | 0  |   ret = _gnutls_supplemental_register(&tmp_entry);  | 
307  | 0  |   if (ret < 0) { | 
308  | 0  |     gnutls_free(tmp_entry.name);  | 
309  | 0  |   }  | 
310  |  | 
  | 
311  | 0  |   _gnutls_disable_tls13 = 1;  | 
312  |  | 
  | 
313  | 0  |   return ret;  | 
314  | 0  | }  | 
315  |  |  | 
316  |  | /**  | 
317  |  |  * gnutls_session_supplemental_register:  | 
318  |  |  * @session: the session for which this will be registered  | 
319  |  |  * @name: the name of the supplemental data to register  | 
320  |  |  * @type: the type of the supplemental data format  | 
321  |  |  * @recv_func: the function to receive the data  | 
322  |  |  * @send_func: the function to send the data  | 
323  |  |  * @flags: must be zero  | 
324  |  |  *  | 
325  |  |  * This function will register a new supplemental data type (rfc4680).  | 
326  |  |  * The registered supplemental functions will be used for that specific  | 
327  |  |  * session. The provided @type must be an unassigned type in  | 
328  |  |  * %gnutls_supplemental_data_format_type_t.  | 
329  |  |  *  | 
330  |  |  * If the type is already registered or handled by GnuTLS internally  | 
331  |  |  * %GNUTLS_E_ALREADY_REGISTERED will be returned.  | 
332  |  |  *  | 
333  |  |  * As supplemental data are not defined under TLS 1.3, this function will  | 
334  |  |  * disable TLS 1.3 support for the given session.  | 
335  |  |  *  | 
336  |  |  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.  | 
337  |  |  *  | 
338  |  |  * Since: 3.5.5  | 
339  |  |  **/  | 
340  |  | int gnutls_session_supplemental_register(  | 
341  |  |   gnutls_session_t session, const char *name,  | 
342  |  |   gnutls_supplemental_data_format_type_t type,  | 
343  |  |   gnutls_supp_recv_func recv_func, gnutls_supp_send_func send_func,  | 
344  |  |   unsigned flags)  | 
345  | 0  | { | 
346  | 0  |   gnutls_supplemental_entry_st tmp_entry;  | 
347  | 0  |   gnutls_supplemental_entry_st *p;  | 
348  | 0  |   unsigned i;  | 
349  |  | 
  | 
350  | 0  |   tmp_entry.name = NULL;  | 
351  | 0  |   tmp_entry.type = type;  | 
352  | 0  |   tmp_entry.supp_recv_func = recv_func;  | 
353  | 0  |   tmp_entry.supp_send_func = send_func;  | 
354  |  | 
  | 
355  | 0  |   for (i = 0; i < suppfunc_size; i++) { | 
356  | 0  |     if (type == suppfunc[i].type)  | 
357  | 0  |       return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);  | 
358  | 0  |   }  | 
359  |  |  | 
360  | 0  |   p = gnutls_realloc(session->internals.rsup,  | 
361  | 0  |          sizeof(gnutls_supplemental_entry_st) *  | 
362  | 0  |            (session->internals.rsup_size + 1));  | 
363  | 0  |   if (!p)  | 
364  | 0  |     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);  | 
365  |  |  | 
366  | 0  |   session->internals.rsup = p;  | 
367  |  | 
  | 
368  | 0  |   memcpy(&session->internals.rsup[session->internals.rsup_size],  | 
369  | 0  |          &tmp_entry, sizeof(tmp_entry));  | 
370  | 0  |   session->internals.rsup_size++;  | 
371  |  | 
  | 
372  | 0  |   session->internals.flags |= INT_FLAG_NO_TLS13;  | 
373  |  | 
  | 
374  | 0  |   return GNUTLS_E_SUCCESS;  | 
375  | 0  | }  | 
376  |  |  | 
377  |  | /**  | 
378  |  |  * gnutls_supplemental_recv:  | 
379  |  |  * @session: is a #gnutls_session_t type.  | 
380  |  |  * @do_recv_supplemental: non-zero in order to expect supplemental data  | 
381  |  |  *  | 
382  |  |  * This function is to be called by an extension handler to  | 
383  |  |  * instruct gnutls to attempt to receive supplemental data  | 
384  |  |  * during the handshake process.  | 
385  |  |  *  | 
386  |  |  * Since: 3.4.0  | 
387  |  |  **/  | 
388  |  | void gnutls_supplemental_recv(gnutls_session_t session,  | 
389  |  |             unsigned do_recv_supplemental)  | 
390  | 0  | { | 
391  | 0  |   session->security_parameters.do_recv_supplemental =  | 
392  | 0  |     do_recv_supplemental;  | 
393  | 0  | }  | 
394  |  |  | 
395  |  | /**  | 
396  |  |  * gnutls_supplemental_send:  | 
397  |  |  * @session: is a #gnutls_session_t type.  | 
398  |  |  * @do_send_supplemental: non-zero in order to send supplemental data  | 
399  |  |  *  | 
400  |  |  * This function is to be called by an extension handler to  | 
401  |  |  * instruct gnutls to send supplemental data during the handshake process.  | 
402  |  |  *  | 
403  |  |  * Since: 3.4.0  | 
404  |  |  **/  | 
405  |  | void gnutls_supplemental_send(gnutls_session_t session,  | 
406  |  |             unsigned do_send_supplemental)  | 
407  | 0  | { | 
408  | 0  |   session->security_parameters.do_send_supplemental =  | 
409  | 0  |     do_send_supplemental;  | 
410  | 0  | }  |