Coverage Report

Created: 2025-03-18 06:55

/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
}