Coverage Report

Created: 2023-03-26 08:33

/src/gnutls/lib/ext/server_name.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
3
 * Copyright (C) 2017 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
#include "gnutls_int.h"
25
#include "auth.h"
26
#include "errors.h"
27
#include "num.h"
28
#include "str.h"
29
#include <ext/server_name.h>
30
#include "hello_ext_lib.h"
31
32
static int _gnutls_server_name_recv_params(gnutls_session_t session,
33
             const uint8_t * data,
34
             size_t data_size);
35
static int _gnutls_server_name_send_params(gnutls_session_t session,
36
             gnutls_buffer_st * extdata);
37
38
int
39
_gnutls_server_name_set_raw(gnutls_session_t session,
40
          gnutls_server_name_type_t type,
41
          const void *name, size_t name_length);
42
43
const hello_ext_entry_st ext_mod_server_name = {
44
  .name = "Server Name Indication",
45
  .tls_id = 0,
46
  .gid = GNUTLS_EXTENSION_SERVER_NAME,
47
  .validity =
48
      GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
49
      GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_EE |
50
      GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
51
  .client_parse_point = GNUTLS_EXT_MANDATORY,
52
  .server_parse_point = GNUTLS_EXT_MANDATORY,
53
  .recv_func = _gnutls_server_name_recv_params,
54
  .send_func = _gnutls_server_name_send_params,
55
  .pack_func = _gnutls_hello_ext_default_pack,
56
  .unpack_func = _gnutls_hello_ext_default_unpack,
57
  .deinit_func = _gnutls_hello_ext_default_deinit,
58
  .cannot_be_overriden = 1
59
};
60
61
/*
62
 * In case of a server: if a NAME_DNS extension type is received then
63
 * it stores into the session the value of NAME_DNS. The server may
64
 * use gnutls_ext_get_server_name(), in order to access it.
65
 *
66
 * In case of a client: If a proper NAME_DNS extension type is found
67
 * in the session then it sends the extension to the peer.
68
 *
69
 */
70
static int
71
_gnutls_server_name_recv_params(gnutls_session_t session,
72
        const uint8_t * data, size_t data_size)
73
0
{
74
0
  const unsigned char *p;
75
0
  uint16_t len, type;
76
0
  gnutls_datum_t name;
77
78
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
79
0
    DECR_LENGTH_RET(data_size, 2,
80
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
81
0
    len = _gnutls_read_uint16(data);
82
0
    if (len == 0)
83
0
      return
84
0
          gnutls_assert_val
85
0
          (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
86
87
0
    if (len != data_size) {
88
0
      gnutls_assert();
89
0
      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
90
0
    }
91
92
0
    p = data + 2;
93
94
0
    while (data_size > 0) {
95
0
      DECR_LEN(data_size, 1);
96
0
      type = *p;
97
0
      p++;
98
99
0
      DECR_LEN(data_size, 2);
100
0
      len = _gnutls_read_uint16(p);
101
0
      p += 2;
102
103
0
      if (len == 0) {
104
0
        _gnutls_handshake_log
105
0
            ("HSK[%p]: Received server name size of zero\n",
106
0
             session);
107
0
        return
108
0
            gnutls_assert_val
109
0
            (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
110
0
      }
111
112
0
      DECR_LEN(data_size, len);
113
114
0
      if (type == 0) { /* NAME_DNS */
115
0
        if (!_gnutls_dnsname_is_valid((char *)p, len)) {
116
0
          _gnutls_handshake_log
117
0
              ("HSK[%p]: Server name is not acceptable: '%.*s'\n",
118
0
               session, (int)len, p);
119
0
          return
120
0
              gnutls_assert_val
121
0
              (GNUTLS_E_RECEIVED_DISALLOWED_NAME);
122
0
        }
123
124
0
        name.data = (void *)p;
125
0
        name.size = len;
126
127
0
        _gnutls_hello_ext_unset_priv(session,
128
0
                   GNUTLS_EXTENSION_SERVER_NAME);
129
0
        return _gnutls_hello_ext_set_datum(session,
130
0
                   GNUTLS_EXTENSION_SERVER_NAME,
131
0
                   &name);
132
0
      }
133
0
      p += len;
134
135
0
    }
136
137
0
  }
138
139
0
  return 0;
140
0
}
141
142
/* returns data_size or a negative number on failure
143
 */
144
static int
145
_gnutls_server_name_send_params(gnutls_session_t session,
146
        gnutls_buffer_st * extdata)
147
0
{
148
0
  int total_size = 0, ret;
149
0
  gnutls_datum_t name;
150
151
0
  ret =
152
0
      _gnutls_hello_ext_get_datum(session, GNUTLS_EXTENSION_SERVER_NAME,
153
0
          &name);
154
0
  if (ret < 0)
155
0
    return 0;
156
157
  /* this function sends the client extension data (dnsname)
158
   */
159
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
160
0
    if (name.size == 0)
161
0
      return 0;
162
163
    /* uint8_t + uint16_t + size
164
     */
165
0
    total_size = 2 + 1 + 2 + name.size;
166
167
    /* UINT16: write total size of all names
168
     */
169
0
    ret = _gnutls_buffer_append_prefix(extdata, 16, total_size - 2);
170
0
    if (ret < 0)
171
0
      return gnutls_assert_val(ret);
172
173
    /* UINT8: type of this extension
174
     * UINT16: size of the first name
175
     * LEN: the actual server name.
176
     */
177
0
    ret = _gnutls_buffer_append_prefix(extdata, 8, 0);
178
0
    if (ret < 0)
179
0
      return gnutls_assert_val(ret);
180
181
0
    _gnutls_debug_log("HSK[%p]: sent server name: '%.*s'\n",
182
0
          session, name.size, name.data);
183
184
0
    ret =
185
0
        _gnutls_buffer_append_data_prefix
186
0
        (extdata, 16, name.data, name.size);
187
0
    if (ret < 0)
188
0
      return gnutls_assert_val(ret);
189
0
  } else {
190
0
    return 0;
191
0
  }
192
193
0
  return total_size;
194
0
}
195
196
/**
197
 * gnutls_server_name_get:
198
 * @session: is a #gnutls_session_t type.
199
 * @data: will hold the data
200
 * @data_length: will hold the data length. Must hold the maximum size of data.
201
 * @type: will hold the server name indicator type
202
 * @indx: is the index of the server_name
203
 *
204
 * This function will allow you to get the name indication (if any), a
205
 * client has sent.  The name indication may be any of the enumeration
206
 * gnutls_server_name_type_t.
207
 *
208
 * If @type is GNUTLS_NAME_DNS, then this function is to be used by
209
 * servers that support virtual hosting, and the data will be a null
210
 * terminated IDNA ACE string (prior to GnuTLS 3.4.0 it was a UTF-8 string).
211
 *
212
 * If @data has not enough size to hold the server name
213
 * GNUTLS_E_SHORT_MEMORY_BUFFER is returned, and @data_length will
214
 * hold the required size.
215
 *
216
 * @indx is used to retrieve more than one server names (if sent by
217
 * the client).  The first server name has an index of 0, the second 1
218
 * and so on.  If no name with the given index exists
219
 * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
220
 *
221
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, on UTF-8
222
 *  decoding error %GNUTLS_E_IDNA_ERROR is returned, otherwise a negative
223
 *  error code is returned.
224
 **/
225
int
226
gnutls_server_name_get(gnutls_session_t session, void *data,
227
           size_t *data_length,
228
           unsigned int *type, unsigned int indx)
229
0
{
230
0
  char *_data = data;
231
0
  gnutls_datum_t name;
232
0
  int ret;
233
234
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
235
0
    gnutls_assert();
236
0
    return GNUTLS_E_INVALID_REQUEST;
237
0
  }
238
239
0
  if (indx != 0)
240
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
241
242
0
  ret =
243
0
      _gnutls_hello_ext_get_datum(session, GNUTLS_EXTENSION_SERVER_NAME,
244
0
          &name);
245
0
  if (ret < 0) {
246
0
    gnutls_assert();
247
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
248
0
  }
249
250
0
  if (name.size == 0) {
251
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
252
0
  }
253
254
0
  *type = GNUTLS_NAME_DNS;
255
256
0
  if (*data_length > name.size) { /* greater since we need one extra byte for the null */
257
0
    *data_length = name.size;
258
0
    memcpy(data, name.data, *data_length);
259
260
    /* null terminate */
261
0
    _data[(*data_length)] = 0;
262
263
0
  } else {
264
0
    *data_length = name.size + 1;
265
0
    ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
266
0
    goto cleanup;
267
0
  }
268
269
0
  ret = 0;
270
0
 cleanup:
271
0
  return ret;
272
0
}
273
274
/* This does not do any conversion not perform any check */
275
int
276
_gnutls_server_name_set_raw(gnutls_session_t session,
277
          gnutls_server_name_type_t type,
278
          const void *name, size_t name_length)
279
0
{
280
0
  int ret;
281
0
  gnutls_datum_t dname;
282
283
0
  if (name_length >= MAX_SERVER_NAME_SIZE) {
284
0
    return GNUTLS_E_INVALID_REQUEST;
285
0
  }
286
287
0
  _gnutls_hello_ext_unset_priv(session, GNUTLS_EXTENSION_SERVER_NAME);
288
289
0
  dname.data = (void *)name;
290
0
  dname.size = name_length;
291
292
0
  ret =
293
0
      _gnutls_hello_ext_set_datum(session, GNUTLS_EXTENSION_SERVER_NAME,
294
0
          &dname);
295
0
  if (ret < 0)
296
0
    return gnutls_assert_val(ret);
297
298
0
  return 0;
299
0
}
300
301
/**
302
 * gnutls_server_name_set:
303
 * @session: is a #gnutls_session_t type.
304
 * @type: specifies the indicator type
305
 * @name: is a string that contains the server name.
306
 * @name_length: holds the length of name excluding the terminating null byte
307
 *
308
 * This function is to be used by clients that want to inform (via a
309
 * TLS extension mechanism) the server of the name they connected to.
310
 * This should be used by clients that connect to servers that do
311
 * virtual hosting.
312
 *
313
 * The value of @name depends on the @type type.  In case of
314
 * %GNUTLS_NAME_DNS, a UTF-8 null-terminated domain name string,
315
 * without the trailing dot, is expected.
316
 *
317
 * IPv4 or IPv6 addresses are not permitted to be set by this function.
318
 * If the function is called with a name of @name_length zero it will clear
319
 * all server names set.
320
 *
321
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
322
 *   otherwise a negative error code is returned.
323
 **/
324
int
325
gnutls_server_name_set(gnutls_session_t session,
326
           gnutls_server_name_type_t type,
327
           const void *name, size_t name_length)
328
0
{
329
0
  int ret;
330
0
  gnutls_datum_t idn_name = { NULL, 0 };
331
332
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
333
0
    gnutls_assert();
334
0
    return GNUTLS_E_INVALID_REQUEST;
335
0
  }
336
337
0
  if (name_length == 0) { /* unset extension */
338
0
    _gnutls_hello_ext_unset_priv(session,
339
0
               GNUTLS_EXTENSION_SERVER_NAME);
340
0
    return 0;
341
0
  }
342
343
0
  ret = gnutls_idna_map(name, name_length, &idn_name, 0);
344
0
  if (ret < 0) {
345
0
    _gnutls_debug_log
346
0
        ("unable to convert name %s to IDNA2008 format\n",
347
0
         (char *)name);
348
0
    return ret;
349
0
  }
350
351
0
  name = idn_name.data;
352
0
  name_length = idn_name.size;
353
354
0
  ret = _gnutls_server_name_set_raw(session, type, name, name_length);
355
0
  gnutls_free(idn_name.data);
356
357
0
  return ret;
358
0
}
359
360
unsigned _gnutls_server_name_matches_resumed(gnutls_session_t session)
361
0
{
362
0
  gnutls_datum_t name1, name2;
363
0
  int ret;
364
365
0
  ret =
366
0
      _gnutls_hello_ext_get_datum(session,
367
0
          GNUTLS_EXTENSION_SERVER_NAME, &name1);
368
0
  if (ret < 0) {   /* no server name in this session */
369
0
    name1.data = NULL;
370
0
    name1.size = 0;
371
0
  }
372
373
0
  ret =
374
0
      _gnutls_hello_ext_get_resumed_datum(session,
375
0
            GNUTLS_EXTENSION_SERVER_NAME,
376
0
            &name2);
377
0
  if (ret < 0) {   /* no server name in this session */
378
0
    name2.data = NULL;
379
0
    name2.size = 0;
380
0
  }
381
382
0
  if (name1.data == NULL || name2.data == NULL) {
383
0
    if (name1.data == name2.data)
384
0
      return 1;
385
0
    else
386
0
      return 0;
387
0
  }
388
389
0
  if (name1.size != name2.size)
390
0
    return 0;
391
392
0
  if (memcmp(name1.data, name2.data, name1.size) != 0)
393
0
    return 0;
394
395
0
  return 1;
396
0
}