Coverage Report

Created: 2023-03-26 07:33

/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] =
144
0
        ((buf->length - sizepos - 4) >> 8) & 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 =
167
0
        gen_supplemental(session, &session->internals.rsup[i], 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
185
0
      ("EXT[%p]: Sending %d bytes of supplemental data\n", session,
186
0
       (int)buf->length);
187
188
0
  return buf->length - init_pos;
189
0
}
190
191
int
192
_gnutls_parse_supplemental(gnutls_session_t session,
193
         const uint8_t * data, int datalen)
194
0
{
195
0
  const uint8_t *p = data;
196
0
  size_t dsize = datalen;
197
0
  size_t total_size;
198
199
0
  DECR_LEN(dsize, 3);
200
0
  total_size = _gnutls_read_uint24(p);
201
0
  p += 3;
202
203
0
  if (dsize != total_size) {
204
0
    gnutls_assert();
205
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
206
0
  }
207
208
0
  do {
209
0
    uint16_t supp_data_type;
210
0
    uint16_t supp_data_length;
211
0
    gnutls_supp_recv_func recv_func;
212
213
0
    DECR_LEN(dsize, 2);
214
0
    supp_data_type = _gnutls_read_uint16(p);
215
0
    p += 2;
216
217
0
    DECR_LEN(dsize, 2);
218
0
    supp_data_length = _gnutls_read_uint16(p);
219
0
    p += 2;
220
221
0
    _gnutls_debug_log
222
0
        ("EXT[%p]: Got supplemental type=%02x length=%d\n",
223
0
         session, supp_data_type, supp_data_length);
224
225
0
    recv_func = get_supp_func_recv(session, supp_data_type);
226
0
    if (recv_func) {
227
0
      int ret = recv_func(session, p, supp_data_length);
228
0
      if (ret < 0) {
229
0
        gnutls_assert();
230
0
        return ret;
231
0
      }
232
0
    } else {
233
0
      gnutls_assert();
234
0
      return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
235
0
    }
236
237
0
    DECR_LEN(dsize, supp_data_length);
238
0
    p += supp_data_length;
239
0
  }
240
0
  while (dsize > 0);
241
242
0
  return 0;
243
0
}
244
245
static int _gnutls_supplemental_register(gnutls_supplemental_entry_st * entry)
246
0
{
247
0
  gnutls_supplemental_entry_st *p;
248
0
  unsigned i;
249
250
0
  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
0
  }
254
255
0
  if (unlikely(INT_ADD_OVERFLOW(suppfunc_size, 1))) {
256
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
257
0
  }
258
259
0
  p = _gnutls_reallocarray_fast(suppfunc, suppfunc_size + 1,
260
0
              sizeof(*suppfunc));
261
0
  if (!p) {
262
0
    gnutls_assert();
263
0
    return GNUTLS_E_MEMORY_ERROR;
264
0
  }
265
266
0
  suppfunc = p;
267
268
0
  memcpy(&suppfunc[suppfunc_size], entry, sizeof(*entry));
269
270
0
  suppfunc_size++;
271
272
0
  return GNUTLS_E_SUCCESS;
273
0
}
274
275
/**
276
 * gnutls_supplemental_register:
277
 * @name: the name of the supplemental data to register
278
 * @type: the type of the supplemental data format
279
 * @recv_func: the function to receive the data
280
 * @send_func: the function to send the data
281
 *
282
 * This function will register a new supplemental data type (rfc4680).
283
 * The registered data will remain until gnutls_global_deinit()
284
 * is called. The provided @type must be an unassigned type in
285
 * %gnutls_supplemental_data_format_type_t. If the type is already
286
 * registered or handled by GnuTLS internally %GNUTLS_E_ALREADY_REGISTERED
287
 * will be returned.
288
 *
289
 * This function is not thread safe. As supplemental data are not defined under
290
 * TLS 1.3, this function will disable TLS 1.3 support globally.
291
 *
292
 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
293
 *
294
 * Since: 3.4.0
295
 **/
296
int
297
gnutls_supplemental_register(const char *name,
298
           gnutls_supplemental_data_format_type_t type,
299
           gnutls_supp_recv_func recv_func,
300
           gnutls_supp_send_func send_func)
301
0
{
302
0
  gnutls_supplemental_entry_st tmp_entry;
303
0
  int ret;
304
305
0
  tmp_entry.name = gnutls_strdup(name);
306
0
  tmp_entry.type = type;
307
0
  tmp_entry.supp_recv_func = recv_func;
308
0
  tmp_entry.supp_send_func = send_func;
309
310
0
  ret = _gnutls_supplemental_register(&tmp_entry);
311
0
  if (ret < 0) {
312
0
    gnutls_free(tmp_entry.name);
313
0
  }
314
315
0
  _gnutls_disable_tls13 = 1;
316
317
0
  return ret;
318
0
}
319
320
/**
321
 * gnutls_session_supplemental_register:
322
 * @session: the session for which this will be registered
323
 * @name: the name of the supplemental data to register
324
 * @type: the type of the supplemental data format
325
 * @recv_func: the function to receive the data
326
 * @send_func: the function to send the data
327
 * @flags: must be zero
328
 *
329
 * This function will register a new supplemental data type (rfc4680).
330
 * The registered supplemental functions will be used for that specific
331
 * session. The provided @type must be an unassigned type in
332
 * %gnutls_supplemental_data_format_type_t.
333
 *
334
 * If the type is already registered or handled by GnuTLS internally
335
 * %GNUTLS_E_ALREADY_REGISTERED will be returned.
336
 *
337
 * As supplemental data are not defined under TLS 1.3, this function will
338
 * disable TLS 1.3 support for the given session.
339
 *
340
 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
341
 *
342
 * Since: 3.5.5
343
 **/
344
int
345
gnutls_session_supplemental_register(gnutls_session_t session, const char *name,
346
             gnutls_supplemental_data_format_type_t
347
             type, gnutls_supp_recv_func recv_func,
348
             gnutls_supp_send_func send_func,
349
             unsigned flags)
350
0
{
351
0
  gnutls_supplemental_entry_st tmp_entry;
352
0
  gnutls_supplemental_entry_st *p;
353
0
  unsigned i;
354
355
0
  tmp_entry.name = NULL;
356
0
  tmp_entry.type = type;
357
0
  tmp_entry.supp_recv_func = recv_func;
358
0
  tmp_entry.supp_send_func = send_func;
359
360
0
  for (i = 0; i < suppfunc_size; i++) {
361
0
    if (type == suppfunc[i].type)
362
0
      return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
363
0
  }
364
365
0
  p = gnutls_realloc(session->internals.rsup,
366
0
         sizeof(gnutls_supplemental_entry_st) *
367
0
         (session->internals.rsup_size + 1));
368
0
  if (!p)
369
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
370
371
0
  session->internals.rsup = p;
372
373
0
  memcpy(&session->internals.rsup[session->internals.rsup_size],
374
0
         &tmp_entry, sizeof(tmp_entry));
375
0
  session->internals.rsup_size++;
376
377
0
  session->internals.flags |= INT_FLAG_NO_TLS13;
378
379
0
  return GNUTLS_E_SUCCESS;
380
0
}
381
382
/**
383
 * gnutls_supplemental_recv:
384
 * @session: is a #gnutls_session_t type.
385
 * @do_recv_supplemental: non-zero in order to expect supplemental data
386
 *
387
 * This function is to be called by an extension handler to
388
 * instruct gnutls to attempt to receive supplemental data
389
 * during the handshake process.
390
 *
391
 * Since: 3.4.0
392
 **/
393
void
394
gnutls_supplemental_recv(gnutls_session_t session,
395
       unsigned do_recv_supplemental)
396
0
{
397
0
  session->security_parameters.do_recv_supplemental =
398
0
      do_recv_supplemental;
399
0
}
400
401
/**
402
 * gnutls_supplemental_send:
403
 * @session: is a #gnutls_session_t type.
404
 * @do_send_supplemental: non-zero in order to send supplemental data
405
 *
406
 * This function is to be called by an extension handler to
407
 * instruct gnutls to send supplemental data during the handshake process.
408
 *
409
 * Since: 3.4.0
410
 **/
411
void
412
gnutls_supplemental_send(gnutls_session_t session,
413
       unsigned do_send_supplemental)
414
0
{
415
0
  session->security_parameters.do_send_supplemental =
416
0
      do_send_supplemental;
417
0
}