Coverage Report

Created: 2023-03-26 08:33

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