Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/ext/safe_renegotiation.c
Line
Count
Source (jump to first uncovered line)
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
0
{
52
0
  int ret;
53
0
  sr_ext_st *priv;
54
0
  gnutls_ext_priv_data_t epriv;
55
56
0
  if (session->internals.priorities->sr == SR_DISABLED ||
57
0
      session->internals.priorities->no_extensions) {
58
0
    return 0;
59
0
  }
60
61
0
  ret = _gnutls_hello_ext_get_priv(
62
0
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
63
0
  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
0
  priv = epriv;
72
73
  /* Save data for safe renegotiation. 
74
   */
75
0
  if (vdata_size > MAX_VERIFY_DATA_SIZE) {
76
0
    gnutls_assert();
77
0
    return GNUTLS_E_INTERNAL_ERROR;
78
0
  }
79
80
0
  if ((session->security_parameters.entity == GNUTLS_CLIENT &&
81
0
       dir == 0) ||
82
0
      (session->security_parameters.entity == GNUTLS_SERVER &&
83
0
       dir == 1)) {
84
0
    priv->client_verify_data_len = vdata_size;
85
0
    memcpy(priv->client_verify_data, vdata, vdata_size);
86
0
  } else {
87
0
    priv->server_verify_data_len = vdata_size;
88
0
    memcpy(priv->server_verify_data, vdata, vdata_size);
89
0
  }
90
91
0
  return 0;
92
0
}
93
94
int _gnutls_ext_sr_verify(gnutls_session_t session)
95
0
{
96
0
  int ret;
97
0
  sr_ext_st *priv = NULL;
98
0
  gnutls_ext_priv_data_t epriv;
99
100
0
  if (session->internals.priorities->sr == SR_DISABLED) {
101
0
    gnutls_assert();
102
0
    return 0;
103
0
  }
104
105
0
  ret = _gnutls_hello_ext_get_priv(
106
0
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
107
0
  if (ret >= 0)
108
0
    priv = epriv;
109
110
  /* Safe renegotiation */
111
112
0
  if (priv && priv->safe_renegotiation_received) {
113
0
    if ((priv->ri_extension_data_len <
114
0
         priv->client_verify_data_len) ||
115
0
        (memcmp(priv->ri_extension_data, priv->client_verify_data,
116
0
          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
0
    if (session->security_parameters.entity == GNUTLS_CLIENT) {
125
0
      if ((priv->ri_extension_data_len !=
126
0
           priv->client_verify_data_len +
127
0
             priv->server_verify_data_len) ||
128
0
          memcmp(priv->ri_extension_data +
129
0
             priv->client_verify_data_len,
130
0
           priv->server_verify_data,
131
0
           priv->server_verify_data_len) != 0) {
132
0
        gnutls_assert();
133
0
        _gnutls_handshake_log(
134
0
          "HSK[%p]: Safe renegotiation failed [2]\n",
135
0
          session);
136
0
        return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
137
0
      }
138
0
    } else { /* Make sure there are 0 extra bytes */
139
140
0
      if (priv->ri_extension_data_len !=
141
0
          priv->client_verify_data_len) {
142
0
        gnutls_assert();
143
0
        _gnutls_handshake_log(
144
0
          "HSK[%p]: Safe renegotiation failed [3]\n",
145
0
          session);
146
0
        return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
147
0
      }
148
0
    }
149
150
0
    _gnutls_handshake_log("HSK[%p]: Safe renegotiation succeeded\n",
151
0
              session);
152
0
  } else { /* safe renegotiation not received... */
153
154
0
    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
0
    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
0
    } else {
176
0
      if (session->internals.priorities->sr < SR_SAFE) {
177
0
        _gnutls_handshake_log(
178
0
          "HSK[%p]: Allowing unsafe initial negotiation\n",
179
0
          session);
180
0
      } 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
0
    }
188
0
  }
189
190
0
  return 0;
191
0
}
192
193
/* if a server received the special ciphersuite.
194
 */
195
int _gnutls_ext_sr_recv_cs(gnutls_session_t session)
196
0
{
197
0
  int ret, set = 0;
198
0
  sr_ext_st *priv;
199
0
  gnutls_ext_priv_data_t epriv;
200
201
0
  ret = _gnutls_hello_ext_get_priv(
202
0
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
203
0
  if (ret < 0) {
204
0
    set = 1;
205
0
  }
206
207
0
  if (set != 0) {
208
0
    priv = gnutls_calloc(1, sizeof(*priv));
209
0
    if (priv == NULL) {
210
0
      gnutls_assert();
211
0
      return GNUTLS_E_MEMORY_ERROR;
212
0
    }
213
0
    epriv = priv;
214
0
  } else
215
0
    priv = epriv;
216
217
0
  priv->safe_renegotiation_received = 1;
218
0
  priv->connection_using_safe_renegotiation = 1;
219
0
  _gnutls_hello_ext_save_sr(session);
220
221
0
  if (set != 0)
222
0
    _gnutls_hello_ext_set_priv(
223
0
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
224
225
0
  return 0;
226
0
}
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
0
{
258
0
  unsigned int len;
259
0
  sr_ext_st *priv;
260
0
  gnutls_ext_priv_data_t epriv;
261
0
  int set = 0, ret;
262
263
0
  if (data_size == 0)
264
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
265
266
0
  len = data[0];
267
0
  DECR_LEN(data_size, len + 1 /* count the first byte and payload */);
268
269
0
  if (session->internals.priorities->sr == SR_DISABLED) {
270
0
    gnutls_assert();
271
0
    return 0;
272
0
  }
273
274
0
  ret = _gnutls_hello_ext_get_priv(
275
0
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
276
0
  if (ret < 0 && session->security_parameters.entity == GNUTLS_SERVER) {
277
0
    set = 1;
278
0
  } else if (ret < 0) {
279
0
    gnutls_assert();
280
0
    return ret;
281
0
  }
282
283
0
  if (set != 0) {
284
0
    priv = gnutls_calloc(1, sizeof(*priv));
285
0
    if (priv == NULL) {
286
0
      gnutls_assert();
287
0
      return GNUTLS_E_MEMORY_ERROR;
288
0
    }
289
0
    epriv = priv;
290
291
0
    _gnutls_hello_ext_set_priv(
292
0
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
293
0
  } else {
294
0
    priv = epriv;
295
0
  }
296
297
  /* It is not legal to receive this extension on a renegotiation and
298
   * not receive it on the initial negotiation.
299
   */
300
0
  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
0
  if (len > sizeof(priv->ri_extension_data)) {
307
0
    gnutls_assert();
308
0
    return GNUTLS_E_SAFE_RENEGOTIATION_FAILED;
309
0
  }
310
311
0
  if (len > 0)
312
0
    memcpy(priv->ri_extension_data, &data[1], len);
313
0
  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
0
  priv->safe_renegotiation_received = 1;
320
0
  priv->connection_using_safe_renegotiation = 1;
321
322
0
  return 0;
323
0
}
324
325
static int _gnutls_sr_send_params(gnutls_session_t session,
326
          gnutls_buffer_st *extdata)
327
0
{
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
0
  sr_ext_st *priv;
334
0
  int ret, set = 0, len;
335
0
  gnutls_ext_priv_data_t epriv;
336
0
  size_t init_length = extdata->length;
337
338
0
  if (session->internals.priorities->sr == SR_DISABLED) {
339
0
    gnutls_assert();
340
0
    return 0;
341
0
  }
342
343
0
  ret = _gnutls_hello_ext_get_priv(
344
0
    session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, &epriv);
345
0
  if (ret < 0) {
346
0
    set = 1;
347
0
  }
348
349
0
  if (set != 0) {
350
0
    priv = gnutls_calloc(1, sizeof(*priv));
351
0
    if (priv == NULL) {
352
0
      gnutls_assert();
353
0
      return GNUTLS_E_MEMORY_ERROR;
354
0
    }
355
0
    epriv = priv;
356
357
0
    _gnutls_hello_ext_set_priv(
358
0
      session, GNUTLS_EXTENSION_SAFE_RENEGOTIATION, epriv);
359
0
  } else
360
0
    priv = epriv;
361
362
  /* Always offer the extension if we're a client */
363
0
  if (priv->connection_using_safe_renegotiation ||
364
0
      session->security_parameters.entity == GNUTLS_CLIENT) {
365
0
    len = priv->client_verify_data_len;
366
0
    if (session->security_parameters.entity == GNUTLS_SERVER)
367
0
      len += priv->server_verify_data_len;
368
369
0
    ret = _gnutls_buffer_append_prefix(extdata, 8, len);
370
0
    if (ret < 0)
371
0
      return gnutls_assert_val(ret);
372
373
0
    ret = _gnutls_buffer_append_data(extdata,
374
0
             priv->client_verify_data,
375
0
             priv->client_verify_data_len);
376
0
    if (ret < 0)
377
0
      return gnutls_assert_val(ret);
378
379
0
    if (session->security_parameters.entity == GNUTLS_SERVER) {
380
0
      ret = _gnutls_buffer_append_data(
381
0
        extdata, priv->server_verify_data,
382
0
        priv->server_verify_data_len);
383
0
      if (ret < 0)
384
0
        return gnutls_assert_val(ret);
385
0
    }
386
0
  } else
387
0
    return 0;
388
389
0
  return extdata->length - init_length;
390
0
}
391
392
static void _gnutls_sr_deinit_data(gnutls_ext_priv_data_t priv)
393
0
{
394
0
  gnutls_free(priv);
395
0
}
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
}