Coverage Report

Created: 2026-11-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/ext/safe_renegotiation.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2009-2012 Free Software Foundation, Inc.
3
 *
4
 * Author: Steve Dispensa (<dispensa@phonefactor.com>)
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
#include "gnutls_int.h"
24
#include "ext/safe_renegotiation.h"
25
#include "errors.h"
26
27
static int _gnutls_sr_recv_params(gnutls_session_t state, const uint8_t *data,
28
          size_t data_size);
29
static int _gnutls_sr_send_params(gnutls_session_t state, gnutls_buffer_st *);
30
static void _gnutls_sr_deinit_data(gnutls_ext_priv_data_t priv);
31
32
const hello_ext_entry_st ext_mod_sr = {
33
  .name = "Safe Renegotiation",
34
  .tls_id = 65281,
35
  .gid = GNUTLS_EXTENSION_SAFE_RENEGOTIATION,
36
  .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
37
        GNUTLS_EXT_FLAG_CLIENT_HELLO |
38
        GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
39
  .client_parse_point = GNUTLS_EXT_MANDATORY,
40
  .server_parse_point = GNUTLS_EXT_MANDATORY,
41
  .recv_func = _gnutls_sr_recv_params,
42
  .send_func = _gnutls_sr_send_params,
43
  .pack_func = NULL,
44
  .unpack_func = NULL,
45
  .deinit_func = _gnutls_sr_deinit_data,
46
  .cannot_be_overriden = 1
47
};
48
49
int _gnutls_ext_sr_finished(gnutls_session_t session, void *vdata,
50
          size_t vdata_size, int dir)
51
4.68k
{
52
4.68k
  int ret;
53
4.68k
  sr_ext_st *priv;
54
4.68k
  gnutls_ext_priv_data_t epriv;
55
56
4.68k
  if (session->internals.priorities->sr == SR_DISABLED ||
57
4.68k
      session->internals.priorities->no_extensions) {
58
0
    return 0;
59
0
  }
60
61
4.68k
  ret = _gnutls_hello_ext_get_priv(
62
4.68k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
63
4.68k
  if (ret < 0) {
64
0
    gnutls_assert();
65
    /* if a client didn't advertise safe renegotiation, we treat
66
     * it as disabled. */
67
0
    if (session->security_parameters.entity == GNUTLS_SERVER)
68
0
      return 0;
69
0
    return ret;
70
0
  }
71
4.68k
  priv = epriv;
72
73
  /* Save data for safe renegotiation. 
74
   */
75
4.68k
  if (vdata_size > MAX_VERIFY_DATA_SIZE) {
76
0
    gnutls_assert();
77
0
    return GNUTLS_E_INTERNAL_ERROR;
78
0
  }
79
80
4.68k
  if ((session->security_parameters.entity == GNUTLS_CLIENT &&
81
4.68k
       dir == 0) ||
82
0
      (session->security_parameters.entity == GNUTLS_SERVER &&
83
4.68k
       dir == 1)) {
84
4.68k
    priv->client_verify_data_len = vdata_size;
85
4.68k
    memcpy(priv->client_verify_data, vdata, vdata_size);
86
4.68k
  } else {
87
0
    priv->server_verify_data_len = vdata_size;
88
0
    memcpy(priv->server_verify_data, vdata, vdata_size);
89
0
  }
90
91
4.68k
  return 0;
92
4.68k
}
93
94
int _gnutls_ext_sr_verify(gnutls_session_t session)
95
19.7k
{
96
19.7k
  int ret;
97
19.7k
  sr_ext_st *priv = NULL;
98
19.7k
  gnutls_ext_priv_data_t epriv;
99
100
19.7k
  if (session->internals.priorities->sr == SR_DISABLED) {
101
0
    gnutls_assert();
102
0
    return 0;
103
0
  }
104
105
19.7k
  ret = _gnutls_hello_ext_get_priv(
106
19.7k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
107
19.7k
  if (ret >= 0)
108
14.5k
    priv = epriv;
109
110
  /* Safe renegotiation */
111
112
19.7k
  if (priv && priv->safe_renegotiation_received) {
113
4.18k
    if ((priv->ri_extension_data_len <
114
4.18k
         priv->client_verify_data_len) ||
115
4.18k
        !memeq(priv->ri_extension_data, priv->client_verify_data,
116
4.18k
         priv->client_verify_data_len)) {
117
0
      gnutls_assert();
118
0
      _gnutls_handshake_log(
119
0
        "HSK[%p]: Safe renegotiation failed [1]\n",
120
0
        session);
121
0
      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
122
0
    }
123
124
4.18k
    if (session->security_parameters.entity == GNUTLS_CLIENT) {
125
3.29k
      if ((priv->ri_extension_data_len !=
126
3.29k
           priv->client_verify_data_len +
127
3.29k
             priv->server_verify_data_len) ||
128
3.27k
          !memeq(priv->ri_extension_data +
129
3.27k
             priv->client_verify_data_len,
130
3.27k
           priv->server_verify_data,
131
3.27k
           priv->server_verify_data_len)) {
132
17
        gnutls_assert();
133
17
        _gnutls_handshake_log(
134
17
          "HSK[%p]: Safe renegotiation failed [2]\n",
135
17
          session);
136
17
        return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
137
17
      }
138
3.29k
    } else { /* Make sure there are 0 extra bytes */
139
140
890
      if (priv->ri_extension_data_len !=
141
890
          priv->client_verify_data_len) {
142
14
        gnutls_assert();
143
14
        _gnutls_handshake_log(
144
14
          "HSK[%p]: Safe renegotiation failed [3]\n",
145
14
          session);
146
14
        return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
147
14
      }
148
890
    }
149
150
4.15k
    _gnutls_handshake_log("HSK[%p]: Safe renegotiation succeeded\n",
151
4.15k
              session);
152
15.5k
  } else { /* safe renegotiation not received... */
153
154
15.5k
    if (priv && priv->connection_using_safe_renegotiation) {
155
0
      gnutls_assert();
156
0
      _gnutls_handshake_log(
157
0
        "HSK[%p]: Peer previously asked for safe renegotiation\n",
158
0
        session);
159
0
      return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
160
0
    }
161
162
    /* Clients can't tell if it's an initial negotiation */
163
15.5k
    if (session->internals.initial_negotiation_completed) {
164
0
      if (session->internals.priorities->sr < SR_PARTIAL) {
165
0
        _gnutls_handshake_log(
166
0
          "HSK[%p]: Allowing unsafe (re)negotiation\n",
167
0
          session);
168
0
      } else {
169
0
        gnutls_assert();
170
0
        _gnutls_handshake_log(
171
0
          "HSK[%p]: Denying unsafe (re)negotiation\n",
172
0
          session);
173
0
        return GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED;
174
0
      }
175
15.5k
    } else {
176
15.5k
      if (session->internals.priorities->sr < SR_SAFE) {
177
15.5k
        _gnutls_handshake_log(
178
15.5k
          "HSK[%p]: Allowing unsafe initial negotiation\n",
179
15.5k
          session);
180
15.5k
      } else {
181
0
        gnutls_assert();
182
0
        _gnutls_handshake_log(
183
0
          "HSK[%p]: Denying unsafe initial negotiation\n",
184
0
          session);
185
0
        return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
186
0
      }
187
15.5k
    }
188
15.5k
  }
189
190
19.6k
  return 0;
191
19.7k
}
192
193
/* if a server received the special ciphersuite.
194
 */
195
int _gnutls_ext_sr_recv_cs(gnutls_session_t session)
196
2.91k
{
197
2.91k
  int ret, set = 0;
198
2.91k
  sr_ext_st *priv;
199
2.91k
  gnutls_ext_priv_data_t epriv;
200
201
2.91k
  ret = _gnutls_hello_ext_get_priv(
202
2.91k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
203
2.91k
  if (ret < 0) {
204
474
    set = 1;
205
474
  }
206
207
2.91k
  if (set != 0) {
208
474
    priv = gnutls_calloc(1, sizeof(*priv));
209
474
    if (priv == NULL) {
210
0
      gnutls_assert();
211
0
      return GNUTLS_E_MEMORY_ERROR;
212
0
    }
213
474
    epriv = priv;
214
474
  } else
215
2.44k
    priv = epriv;
216
217
2.91k
  priv->safe_renegotiation_received = 1;
218
2.91k
  priv->connection_using_safe_renegotiation = 1;
219
2.91k
  _gnutls_hello_ext_save_sr(session);
220
221
2.91k
  if (set != 0)
222
474
    _gnutls_hello_ext_set_priv(
223
474
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
224
225
2.91k
  return 0;
226
2.91k
}
227
228
int _gnutls_ext_sr_send_cs(gnutls_session_t session)
229
0
{
230
0
  int ret, set = 0;
231
0
  sr_ext_st *priv;
232
0
  gnutls_ext_priv_data_t epriv;
233
234
0
  ret = _gnutls_hello_ext_get_priv(
235
0
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
236
0
  if (ret < 0) {
237
0
    set = 1;
238
0
  }
239
240
0
  if (set != 0) {
241
0
    priv = gnutls_calloc(1, sizeof(*priv));
242
0
    if (priv == NULL) {
243
0
      gnutls_assert();
244
0
      return GNUTLS_E_MEMORY_ERROR;
245
0
    }
246
0
    epriv = priv;
247
248
0
    _gnutls_hello_ext_set_priv(
249
0
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
250
0
  }
251
252
0
  return 0;
253
0
}
254
255
static int _gnutls_sr_recv_params(gnutls_session_t session, const uint8_t *data,
256
          size_t data_size)
257
4.79k
{
258
4.79k
  unsigned int len;
259
4.79k
  sr_ext_st *priv;
260
4.79k
  gnutls_ext_priv_data_t epriv;
261
4.79k
  int set = 0, ret;
262
263
4.79k
  if (data_size == 0)
264
13
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
265
266
4.78k
  len = data[0];
267
4.78k
  DECR_LEN(data_size, len + 1 /* count the first byte and payload */);
268
269
4.75k
  if (session->internals.priorities->sr == SR_DISABLED) {
270
0
    gnutls_assert();
271
0
    return 0;
272
0
  }
273
274
4.75k
  ret = _gnutls_hello_ext_get_priv(
275
4.75k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
276
4.75k
  if (ret < 0 && session->security_parameters.entity == GNUTLS_SERVER) {
277
1.24k
    set = 1;
278
3.50k
  } else if (ret < 0) {
279
0
    gnutls_assert();
280
0
    return ret;
281
0
  }
282
283
4.75k
  if (set != 0) {
284
1.24k
    priv = gnutls_calloc(1, sizeof(*priv));
285
1.24k
    if (priv == NULL) {
286
0
      gnutls_assert();
287
0
      return GNUTLS_E_MEMORY_ERROR;
288
0
    }
289
1.24k
    epriv = priv;
290
291
1.24k
    _gnutls_hello_ext_set_priv(
292
1.24k
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
293
3.50k
  } else {
294
3.50k
    priv = epriv;
295
3.50k
  }
296
297
  /* It is not legal to receive this extension on a renegotiation and
298
   * not receive it on the initial negotiation.
299
   */
300
4.75k
  if (session->internals.initial_negotiation_completed != 0 &&
301
0
      priv->connection_using_safe_renegotiation == 0) {
302
0
    gnutls_assert();
303
0
    return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
304
0
  }
305
306
4.75k
  if (len > sizeof(priv->ri_extension_data)) {
307
7
    gnutls_assert();
308
7
    return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
309
7
  }
310
311
4.74k
  if (len > 0)
312
109
    memcpy(priv->ri_extension_data, &data[1], len);
313
4.74k
  priv->ri_extension_data_len = len;
314
315
  /* "safe renegotiation received" means on *this* handshake; "connection using
316
   * safe renegotiation" means that the initial hello received on the connection
317
   * indicated safe renegotiation.
318
   */
319
4.74k
  priv->safe_renegotiation_received = 1;
320
4.74k
  priv->connection_using_safe_renegotiation = 1;
321
322
4.74k
  return 0;
323
4.75k
}
324
325
static int _gnutls_sr_send_params(gnutls_session_t session,
326
          gnutls_buffer_st *extdata)
327
31.6k
{
328
  /* The format of this extension is a one-byte length of verify data followed
329
   * by the verify data itself. Note that the length byte does not include
330
   * itself; IOW, empty verify data is represented as a length of 0. That means
331
   * the minimum extension is one byte: 0x00.
332
   */
333
31.6k
  sr_ext_st *priv;
334
31.6k
  int ret, set = 0, len;
335
31.6k
  gnutls_ext_priv_data_t epriv;
336
31.6k
  size_t init_length = extdata->length;
337
338
31.6k
  if (session->internals.priorities->sr == SR_DISABLED) {
339
0
    gnutls_assert();
340
0
    return 0;
341
0
  }
342
343
31.6k
  ret = _gnutls_hello_ext_get_priv(
344
31.6k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
345
31.6k
  if (ret < 0) {
346
24.1k
    set = 1;
347
24.1k
  }
348
349
31.6k
  if (set != 0) {
350
24.1k
    priv = gnutls_calloc(1, sizeof(*priv));
351
24.1k
    if (priv == NULL) {
352
0
      gnutls_assert();
353
0
      return GNUTLS_E_MEMORY_ERROR;
354
0
    }
355
24.1k
    epriv = priv;
356
357
24.1k
    _gnutls_hello_ext_set_priv(
358
24.1k
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
359
24.1k
  } else
360
7.46k
    priv = epriv;
361
362
  /* Always offer the extension if we're a client */
363
31.6k
  if (priv->connection_using_safe_renegotiation ||
364
31.6k
      session->security_parameters.entity == GNUTLS_CLIENT) {
365
31.6k
    len = priv->client_verify_data_len;
366
31.6k
    if (session->security_parameters.entity == GNUTLS_SERVER)
367
634
      len += priv->server_verify_data_len;
368
369
31.6k
    ret = _gnutls_buffer_append_uint8(extdata, len);
370
31.6k
    if (ret < 0)
371
0
      return gnutls_assert_val(ret);
372
373
31.6k
    ret = _gnutls_buffer_append_data(extdata,
374
31.6k
             priv->client_verify_data,
375
31.6k
             priv->client_verify_data_len);
376
31.6k
    if (ret < 0)
377
0
      return gnutls_assert_val(ret);
378
379
31.6k
    if (session->security_parameters.entity == GNUTLS_SERVER) {
380
634
      ret = _gnutls_buffer_append_data(
381
634
        extdata, priv->server_verify_data,
382
634
        priv->server_verify_data_len);
383
634
      if (ret < 0)
384
0
        return gnutls_assert_val(ret);
385
634
    }
386
31.6k
  } else
387
0
    return 0;
388
389
31.6k
  return extdata->length - init_length;
390
31.6k
}
391
392
static void _gnutls_sr_deinit_data(gnutls_ext_priv_data_t priv)
393
25.8k
{
394
25.8k
  gnutls_free(priv);
395
25.8k
}
396
397
/**
398
 * gnutls_safe_renegotiation_status:
399
 * @session: is a #gnutls_session_t type.
400
 *
401
 * Can be used to check whether safe renegotiation is being used
402
 * in the current session.
403
 *
404
 * Returns: 0 when safe renegotiation is not used and non (0) when
405
 *   safe renegotiation is used.
406
 *
407
 * Since: 2.10.0
408
 **/
409
unsigned gnutls_safe_renegotiation_status(gnutls_session_t session)
410
0
{
411
0
  int ret;
412
0
  sr_ext_st *priv;
413
0
  gnutls_ext_priv_data_t epriv;
414
415
0
  ret = _gnutls_hello_ext_get_priv(
416
0
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
417
0
  if (ret < 0) {
418
0
    gnutls_assert();
419
0
    return 0;
420
0
  }
421
0
  priv = epriv;
422
423
0
  return priv->connection_using_safe_renegotiation;
424
0
}