Coverage Report

Created: 2025-03-18 06:55

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