Coverage Report

Created: 2026-06-08 06:48

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.33k
{
52
4.33k
  int ret;
53
4.33k
  sr_ext_st *priv;
54
4.33k
  gnutls_ext_priv_data_t epriv;
55
56
4.33k
  if (session->internals.priorities->sr == SR_DISABLED ||
57
4.33k
      session->internals.priorities->no_extensions) {
58
0
    return 0;
59
0
  }
60
61
4.33k
  ret = _gnutls_hello_ext_get_priv(
62
4.33k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
63
4.33k
  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.33k
  priv = epriv;
72
73
  /* Save data for safe renegotiation. 
74
   */
75
4.33k
  if (vdata_size > MAX_VERIFY_DATA_SIZE) {
76
0
    gnutls_assert();
77
0
    return GNUTLS_E_INTERNAL_ERROR;
78
0
  }
79
80
4.33k
  if ((session->security_parameters.entity == GNUTLS_CLIENT &&
81
4.33k
       dir == 0) ||
82
0
      (session->security_parameters.entity == GNUTLS_SERVER &&
83
4.33k
       dir == 1)) {
84
4.33k
    priv->client_verify_data_len = vdata_size;
85
4.33k
    memcpy(priv->client_verify_data, vdata, vdata_size);
86
4.33k
  } 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.33k
  return 0;
92
4.33k
}
93
94
int _gnutls_ext_sr_verify(gnutls_session_t session)
95
15.7k
{
96
15.7k
  int ret;
97
15.7k
  sr_ext_st *priv = NULL;
98
15.7k
  gnutls_ext_priv_data_t epriv;
99
100
15.7k
  if (session->internals.priorities->sr == SR_DISABLED) {
101
0
    gnutls_assert();
102
0
    return 0;
103
0
  }
104
105
15.7k
  ret = _gnutls_hello_ext_get_priv(
106
15.7k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
107
15.7k
  if (ret >= 0)
108
13.8k
    priv = epriv;
109
110
  /* Safe renegotiation */
111
112
15.7k
  if (priv && priv->safe_renegotiation_received) {
113
3.52k
    if ((priv->ri_extension_data_len <
114
3.52k
         priv->client_verify_data_len) ||
115
3.52k
        (memcmp(priv->ri_extension_data, priv->client_verify_data,
116
3.52k
          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
3.52k
    if (session->security_parameters.entity == GNUTLS_CLIENT) {
125
3.22k
      if ((priv->ri_extension_data_len !=
126
3.22k
           priv->client_verify_data_len +
127
3.22k
             priv->server_verify_data_len) ||
128
3.20k
          memcmp(priv->ri_extension_data +
129
3.20k
             priv->client_verify_data_len,
130
3.20k
           priv->server_verify_data,
131
3.20k
           priv->server_verify_data_len) != 0) {
132
19
        gnutls_assert();
133
19
        _gnutls_handshake_log(
134
19
          "HSK[%p]: Safe renegotiation failed [2]\n",
135
19
          session);
136
19
        return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
137
19
      }
138
3.22k
    } else { /* Make sure there are 0 extra bytes */
139
140
296
      if (priv->ri_extension_data_len !=
141
296
          priv->client_verify_data_len) {
142
3
        gnutls_assert();
143
3
        _gnutls_handshake_log(
144
3
          "HSK[%p]: Safe renegotiation failed [3]\n",
145
3
          session);
146
3
        return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
147
3
      }
148
296
    }
149
150
3.50k
    _gnutls_handshake_log("HSK[%p]: Safe renegotiation succeeded\n",
151
3.50k
              session);
152
12.2k
  } else { /* safe renegotiation not received... */
153
154
12.2k
    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
12.2k
    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
12.2k
    } else {
176
12.2k
      if (session->internals.priorities->sr < SR_SAFE) {
177
12.2k
        _gnutls_handshake_log(
178
12.2k
          "HSK[%p]: Allowing unsafe initial negotiation\n",
179
12.2k
          session);
180
12.2k
      } 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
12.2k
    }
188
12.2k
  }
189
190
15.7k
  return 0;
191
15.7k
}
192
193
/* if a server received the special ciphersuite.
194
 */
195
int _gnutls_ext_sr_recv_cs(gnutls_session_t session)
196
1.69k
{
197
1.69k
  int ret, set = 0;
198
1.69k
  sr_ext_st *priv;
199
1.69k
  gnutls_ext_priv_data_t epriv;
200
201
1.69k
  ret = _gnutls_hello_ext_get_priv(
202
1.69k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
203
1.69k
  if (ret < 0) {
204
365
    set = 1;
205
365
  }
206
207
1.69k
  if (set != 0) {
208
365
    priv = gnutls_calloc(1, sizeof(*priv));
209
365
    if (priv == NULL) {
210
0
      gnutls_assert();
211
0
      return GNUTLS_E_MEMORY_ERROR;
212
0
    }
213
365
    epriv = priv;
214
365
  } else
215
1.33k
    priv = epriv;
216
217
1.69k
  priv->safe_renegotiation_received = 1;
218
1.69k
  priv->connection_using_safe_renegotiation = 1;
219
1.69k
  _gnutls_hello_ext_save_sr(session);
220
221
1.69k
  if (set != 0)
222
365
    _gnutls_hello_ext_set_priv(
223
365
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
224
225
1.69k
  return 0;
226
1.69k
}
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.01k
{
258
4.01k
  unsigned int len;
259
4.01k
  sr_ext_st *priv;
260
4.01k
  gnutls_ext_priv_data_t epriv;
261
4.01k
  int set = 0, ret;
262
263
4.01k
  if (data_size == 0)
264
10
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
265
266
4.00k
  len = data[0];
267
4.00k
  DECR_LEN(data_size, len + 1 /* count the first byte and payload */);
268
269
3.98k
  if (session->internals.priorities->sr == SR_DISABLED) {
270
0
    gnutls_assert();
271
0
    return 0;
272
0
  }
273
274
3.98k
  ret = _gnutls_hello_ext_get_priv(
275
3.98k
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
276
3.98k
  if (ret < 0 && session->security_parameters.entity == GNUTLS_SERVER) {
277
559
    set = 1;
278
3.42k
  } else if (ret < 0) {
279
0
    gnutls_assert();
280
0
    return ret;
281
0
  }
282
283
3.98k
  if (set != 0) {
284
559
    priv = gnutls_calloc(1, sizeof(*priv));
285
559
    if (priv == NULL) {
286
0
      gnutls_assert();
287
0
      return GNUTLS_E_MEMORY_ERROR;
288
0
    }
289
559
    epriv = priv;
290
291
559
    _gnutls_hello_ext_set_priv(
292
559
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
293
3.42k
  } else {
294
3.42k
    priv = epriv;
295
3.42k
  }
296
297
  /* It is not legal to receive this extension on a renegotiation and
298
   * not receive it on the initial negotiation.
299
   */
300
3.98k
  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
3.98k
  if (len > sizeof(priv->ri_extension_data)) {
307
5
    gnutls_assert();
308
5
    return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
309
5
  }
310
311
3.98k
  if (len > 0)
312
96
    memcpy(priv->ri_extension_data, &data[1], len);
313
3.98k
  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
3.98k
  priv->safe_renegotiation_received = 1;
320
3.98k
  priv->connection_using_safe_renegotiation = 1;
321
322
3.98k
  return 0;
323
3.98k
}
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.7k
    set = 1;
347
24.7k
  }
348
349
31.6k
  if (set != 0) {
350
24.7k
    priv = gnutls_calloc(1, sizeof(*priv));
351
24.7k
    if (priv == NULL) {
352
0
      gnutls_assert();
353
0
      return GNUTLS_E_MEMORY_ERROR;
354
0
    }
355
24.7k
    epriv = priv;
356
357
24.7k
    _gnutls_hello_ext_set_priv(
358
24.7k
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
359
24.7k
  } else
360
6.86k
    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
55
      len += priv->server_verify_data_len;
368
369
31.6k
    ret = _gnutls_buffer_append_prefix(extdata, 8, 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
55
      ret = _gnutls_buffer_append_data(
381
55
        extdata, priv->server_verify_data,
382
55
        priv->server_verify_data_len);
383
55
      if (ret < 0)
384
0
        return gnutls_assert_val(ret);
385
55
    }
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.6k
{
394
25.6k
  gnutls_free(priv);
395
25.6k
}
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
}