Coverage Report

Created: 2025-11-16 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/ext/supported_versions.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
3
 * Copyright (C) 2017-2018 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
/* This file contains the code for the Max Record Size TLS extension.
25
 */
26
27
#include "gnutls_int.h"
28
#include "errors.h"
29
#include "num.h"
30
#include "hello_ext.h"
31
#include "ext/supported_versions.h"
32
#include "handshake.h"
33
34
static int supported_versions_recv_params(gnutls_session_t session,
35
            const uint8_t *data,
36
            size_t data_size);
37
static int supported_versions_send_params(gnutls_session_t session,
38
            gnutls_buffer_st *extdata);
39
40
const hello_ext_entry_st ext_mod_supported_versions = {
41
  .name = "Supported Versions",
42
  .tls_id = 43,
43
  .gid = GNUTLS_EXTENSION_SUPPORTED_VERSIONS,
44
  .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO |
45
        GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |
46
        GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | GNUTLS_EXT_FLAG_HRR |
47
        GNUTLS_EXT_FLAG_TLS,
48
  .client_parse_point =
49
    GNUTLS_EXT_VERSION_NEG, /* force parsing prior to EXT_TLS extensions */
50
  .server_parse_point = GNUTLS_EXT_VERSION_NEG,
51
  .recv_func = supported_versions_recv_params,
52
  .send_func = supported_versions_send_params,
53
  .pack_func = NULL,
54
  .unpack_func = NULL,
55
  .deinit_func = NULL,
56
  .cannot_be_overriden = 1
57
};
58
59
static int supported_versions_recv_params(gnutls_session_t session,
60
            const uint8_t *data, size_t data_size)
61
12.9k
{
62
12.9k
  const version_entry_st *vers;
63
12.9k
  uint8_t major, minor;
64
12.9k
  size_t bytes;
65
12.9k
  int ret;
66
67
12.9k
  if (session->security_parameters.entity == GNUTLS_SERVER) {
68
3.06k
    const version_entry_st *old_vers;
69
3.06k
    const version_entry_st *cli_vers = NULL;
70
71
3.06k
    vers = _gnutls_version_max(session);
72
3.06k
    old_vers = get_version(session);
73
74
    /* do not parse this extension when we haven't TLS1.3
75
     * enabled. That is because we cannot handle earlier protocol
76
     * negotiation (such as SSL3.0) with this */
77
3.06k
    if (vers && !vers->tls13_sem)
78
28
      return 0;
79
80
3.03k
    DECR_LEN(data_size, 1);
81
3.03k
    bytes = data[0];
82
3.03k
    data++;
83
84
3.03k
    if (bytes % 2 == 1)
85
6
      return gnutls_assert_val(
86
3.03k
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
87
88
3.02k
    DECR_LEN(data_size, bytes);
89
90
3.01k
    if (data_size != 0)
91
38
      return gnutls_assert_val(
92
3.01k
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
93
94
15.8k
    while (bytes > 0) {
95
12.8k
      major = data[0];
96
12.8k
      minor = data[1];
97
12.8k
      data += 2;
98
12.8k
      bytes -= 2;
99
100
12.8k
      _gnutls_handshake_log("EXT[%p]: Found version: %d.%d\n",
101
12.8k
                session, (int)major, (int)minor);
102
103
12.8k
      if (!_gnutls_nversion_is_supported(session, major,
104
12.8k
                 minor))
105
7.53k
        continue;
106
107
      /* Prefer the latest possible version
108
       * regardless of the client's precedence.  See
109
       * https://gitlab.com/gnutls/gnutls/issues/837
110
       * for the rationale.
111
       */
112
5.36k
      if (!cli_vers || major > cli_vers->major ||
113
2.43k
          (major == cli_vers->major &&
114
2.43k
           minor > cli_vers->minor))
115
3.09k
        cli_vers = nversion_to_entry(major, minor);
116
5.36k
    }
117
118
2.98k
    if (!cli_vers)
119
46
      return gnutls_assert_val(
120
2.98k
        GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
121
122
2.93k
    session->security_parameters.pversion = cli_vers;
123
124
2.93k
    _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n",
125
2.93k
              session, (int)cli_vers->major,
126
2.93k
              (int)cli_vers->minor);
127
128
2.93k
    if (old_vers != cli_vers) {
129
      /* regenerate the random value to set
130
       * downgrade sentinel if necessary
131
       */
132
2.90k
      ret = _gnutls_gen_server_random(session, cli_vers->id);
133
2.90k
      if (ret < 0)
134
0
        return gnutls_assert_val(ret);
135
2.90k
    }
136
137
2.93k
    return 0;
138
9.90k
  } else { /* client */
139
140
9.90k
    if (!have_creds_for_tls13(session)) {
141
      /* if we don't have certificate or PSK (which work under TLS1.3)
142
       * don't try to negotiate version using the extension. We fallback
143
       * instead to the normal TLS negotiation which has a cap on TLS1.2.
144
       */
145
0
      return 0;
146
0
    }
147
148
9.90k
    DECR_LEN(data_size, 2);
149
150
9.90k
    if (data_size != 0)
151
14
      return gnutls_assert_val(
152
9.90k
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
153
154
9.88k
    major = data[0];
155
9.88k
    minor = data[1];
156
157
9.88k
    vers = nversion_to_entry(major, minor);
158
9.88k
    if (!vers)
159
8
      return gnutls_assert_val(
160
9.88k
        GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
161
162
9.87k
    set_adv_version(session, major, minor);
163
164
9.87k
    _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n",
165
9.87k
              session, (int)major, (int)minor);
166
167
9.87k
    if (!vers->tls13_sem)
168
5
      return gnutls_assert_val(
169
9.87k
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
170
171
9.87k
    ret = _gnutls_negotiate_version(session, major, minor, 1);
172
9.87k
    if (ret < 0) {
173
0
      gnutls_assert();
174
0
      return ret;
175
0
    }
176
9.87k
  }
177
178
9.87k
  return 0;
179
12.9k
}
180
181
/* returns data_size or a negative number on failure
182
 */
183
static int supported_versions_send_params(gnutls_session_t session,
184
            gnutls_buffer_st *extdata)
185
36.2k
{
186
36.2k
  uint8_t versions[32];
187
36.2k
  size_t versions_size;
188
36.2k
  const version_entry_st *vers;
189
36.2k
  int ret;
190
191
  /* this function sends the client extension data (dnsname) */
192
36.2k
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
193
34.4k
    vers = _gnutls_version_max(session);
194
195
    /* Do not advertise this extension if we are not doing certificate
196
     * or PSK authentication; i.e., do not try to do TLS1.3 if we have
197
     * credentials which do not fit it. */
198
34.4k
    if (!have_creds_for_tls13(session)) {
199
      /* if we don't have certificate or PSK (which work under TLS1.3)
200
       * don't try to negotiate version using the extension. We fallback
201
       * instead to the normal TLS negotiation which has a cap on TLS1.2.
202
       */
203
0
      return 0;
204
0
    }
205
206
    /* do not advertise this extension when we haven't TLS1.3
207
     * enabled. */
208
34.4k
    if (vers && !vers->tls13_sem)
209
0
      return 0;
210
211
34.4k
    ret = _gnutls_write_supported_versions(session, versions,
212
34.4k
                   sizeof(versions));
213
34.4k
    if (ret <=
214
34.4k
        0) /* if this function doesn't succeed do not send anything */
215
0
      return 0;
216
217
34.4k
    versions_size = ret;
218
219
34.4k
    ret = _gnutls_buffer_append_data_prefix(extdata, 8, versions,
220
34.4k
              versions_size);
221
34.4k
    if (ret < 0)
222
0
      return gnutls_assert_val(ret);
223
224
34.4k
    return versions_size + 2;
225
34.4k
  } else {
226
1.81k
    vers = get_version(session);
227
1.81k
    if (unlikely(vers == NULL))
228
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
229
230
    /* don't use this extension to negotiate versions <= 1.2,
231
     * pretend we don't support it, so that we use a single
232
     * code path to negotiate these protocols. */
233
1.81k
    if (!vers->tls13_sem)
234
44
      return 0;
235
236
1.76k
    ret = _gnutls_buffer_append_data(extdata, &vers->major, 1);
237
1.76k
    if (ret < 0)
238
0
      return gnutls_assert_val(ret);
239
240
1.76k
    ret = _gnutls_buffer_append_data(extdata, &vers->minor, 1);
241
1.76k
    if (ret < 0)
242
0
      return gnutls_assert_val(ret);
243
244
1.76k
    return 2;
245
1.76k
  }
246
247
0
  return 0;
248
36.2k
}