Coverage Report

Created: 2024-06-20 06:28

/src/gnutls/lib/ext/supported_versions.c
Line
Count
Source (jump to first uncovered line)
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
0
{
62
0
  const version_entry_st *vers;
63
0
  uint8_t major, minor;
64
0
  size_t bytes;
65
0
  int ret;
66
67
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
68
0
    const version_entry_st *old_vers;
69
0
    const version_entry_st *cli_vers = NULL;
70
71
0
    vers = _gnutls_version_max(session);
72
0
    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
0
    if (vers && !vers->tls13_sem)
78
0
      return 0;
79
80
0
    DECR_LEN(data_size, 1);
81
0
    bytes = data[0];
82
0
    data++;
83
84
0
    if (bytes % 2 == 1)
85
0
      return gnutls_assert_val(
86
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
87
88
0
    DECR_LEN(data_size, bytes);
89
90
0
    if (data_size != 0)
91
0
      return gnutls_assert_val(
92
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
93
94
0
    while (bytes > 0) {
95
0
      major = data[0];
96
0
      minor = data[1];
97
0
      data += 2;
98
0
      bytes -= 2;
99
100
0
      _gnutls_handshake_log("EXT[%p]: Found version: %d.%d\n",
101
0
                session, (int)major, (int)minor);
102
103
0
      if (!_gnutls_nversion_is_supported(session, major,
104
0
                 minor))
105
0
        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
0
      if (!cli_vers || major > cli_vers->major ||
113
0
          (major == cli_vers->major &&
114
0
           minor > cli_vers->minor))
115
0
        cli_vers = nversion_to_entry(major, minor);
116
0
    }
117
118
0
    if (!cli_vers)
119
0
      return gnutls_assert_val(
120
0
        GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
121
122
0
    session->security_parameters.pversion = cli_vers;
123
124
0
    _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n",
125
0
              session, (int)cli_vers->major,
126
0
              (int)cli_vers->minor);
127
128
0
    if (old_vers != cli_vers) {
129
      /* regenerate the random value to set
130
       * downgrade sentinel if necessary
131
       */
132
0
      ret = _gnutls_gen_server_random(session, cli_vers->id);
133
0
      if (ret < 0)
134
0
        return gnutls_assert_val(ret);
135
0
    }
136
137
0
    return 0;
138
0
  } else { /* client */
139
140
0
    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
0
    DECR_LEN(data_size, 2);
149
150
0
    if (data_size != 0)
151
0
      return gnutls_assert_val(
152
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
153
154
0
    major = data[0];
155
0
    minor = data[1];
156
157
0
    vers = nversion_to_entry(major, minor);
158
0
    if (!vers)
159
0
      return gnutls_assert_val(
160
0
        GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
161
162
0
    set_adv_version(session, major, minor);
163
164
0
    _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n",
165
0
              session, (int)major, (int)minor);
166
167
0
    if (!vers->tls13_sem)
168
0
      return gnutls_assert_val(
169
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
170
171
0
    ret = _gnutls_negotiate_version(session, major, minor, 1);
172
0
    if (ret < 0) {
173
0
      gnutls_assert();
174
0
      return ret;
175
0
    }
176
0
  }
177
178
0
  return 0;
179
0
}
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
0
{
186
0
  uint8_t versions[32];
187
0
  size_t versions_size;
188
0
  const version_entry_st *vers;
189
0
  int ret;
190
191
  /* this function sends the client extension data (dnsname) */
192
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
193
0
    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
0
    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
0
    if (vers && !vers->tls13_sem)
209
0
      return 0;
210
211
0
    ret = _gnutls_write_supported_versions(session, versions,
212
0
                   sizeof(versions));
213
0
    if (ret <=
214
0
        0) /* if this function doesn't succeed do not send anything */
215
0
      return 0;
216
217
0
    versions_size = ret;
218
219
0
    ret = _gnutls_buffer_append_data_prefix(extdata, 8, versions,
220
0
              versions_size);
221
0
    if (ret < 0)
222
0
      return gnutls_assert_val(ret);
223
224
0
    return versions_size + 2;
225
0
  } else {
226
0
    vers = get_version(session);
227
0
    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
0
    if (!vers->tls13_sem)
234
0
      return 0;
235
236
0
    ret = _gnutls_buffer_append_data(extdata, &vers->major, 1);
237
0
    if (ret < 0)
238
0
      return gnutls_assert_val(ret);
239
240
0
    ret = _gnutls_buffer_append_data(extdata, &vers->minor, 1);
241
0
    if (ret < 0)
242
0
      return gnutls_assert_val(ret);
243
244
0
    return 2;
245
0
  }
246
247
0
  return 0;
248
0
}