Coverage Report

Created: 2024-02-11 06:58

/src/gnutls/lib/buffers.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
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
/*
24
 * This file holds all the buffering code used in gnutls.
25
 * The buffering code works as:
26
 *
27
 * RECORD LAYER:
28
 *  1. uses a buffer to hold data (application/handshake),
29
 *    we got but they were not requested, yet.
30
 *  (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
31
 *
32
 *  2. uses a buffer to hold data that were incomplete (ie the read/write
33
 *    was interrupted)
34
 *  (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
35
 *
36
 * HANDSHAKE LAYER:
37
 *  1. Uses buffer to hold the last received handshake message.
38
 *  (see _gnutls_handshake_hash_buffer_put() etc.)
39
 *
40
 */
41
42
#include "gnutls_int.h"
43
#include "errors.h"
44
#include "num.h"
45
#include "record.h"
46
#include "buffers.h"
47
#include "mbuffers.h"
48
#include "state.h"
49
#include "dtls.h"
50
#include "system.h"
51
#include "constate.h" /* gnutls_epoch_get */
52
#include "handshake.h" /* remaining_time() */
53
#include <errno.h>
54
#include "system.h"
55
#include "debug.h"
56
57
#ifndef EAGAIN
58
#define EAGAIN EWOULDBLOCK
59
#endif
60
61
/* this is the maximum number of messages allowed to queue.
62
 */
63
0
#define MAX_QUEUE 32
64
65
/* Buffers received packets of type APPLICATION DATA,
66
 * HANDSHAKE DATA and HEARTBEAT.
67
 */
68
void _gnutls_record_buffer_put(gnutls_session_t session, content_type_t type,
69
             uint64_t seq, mbuffer_st *bufel)
70
0
{
71
0
  bufel->type = type;
72
0
  bufel->record_sequence = seq;
73
74
0
  _mbuffer_enqueue(&session->internals.record_buffer, bufel);
75
0
  _gnutls_buffers_log("BUF[REC]: Inserted %d bytes of Data(%d)\n",
76
0
          (int)bufel->msg.size, (int)type);
77
78
0
  return;
79
0
}
80
81
/**
82
 * gnutls_record_check_pending:
83
 * @session: is a #gnutls_session_t type.
84
 *
85
 * This function checks if there are unread data
86
 * in the gnutls buffers. If the return value is
87
 * non-zero the next call to gnutls_record_recv()
88
 * is guaranteed not to block.
89
 *
90
 * Returns: Returns the size of the data or zero.
91
 **/
92
size_t gnutls_record_check_pending(gnutls_session_t session)
93
0
{
94
0
  return _gnutls_record_buffer_get_size(session);
95
0
}
96
97
/**
98
 * gnutls_record_check_corked:
99
 * @session: is a #gnutls_session_t type.
100
 *
101
 * This function checks if there pending corked
102
 * data in the gnutls buffers --see gnutls_record_cork().
103
 *
104
 * Returns: Returns the size of the corked data or zero.
105
 *
106
 * Since: 3.2.8
107
 **/
108
size_t gnutls_record_check_corked(gnutls_session_t session)
109
0
{
110
0
  return session->internals.record_presend_buffer.length;
111
0
}
112
113
int _gnutls_record_buffer_get(content_type_t type, gnutls_session_t session,
114
            uint8_t *data, size_t length, uint8_t seq[8])
115
0
{
116
0
  gnutls_datum_t msg;
117
0
  mbuffer_st *bufel;
118
119
0
  if (length == 0 || data == NULL) {
120
0
    gnutls_assert();
121
0
    return GNUTLS_E_INVALID_REQUEST;
122
0
  }
123
124
0
  bufel = _mbuffer_head_get_first(&session->internals.record_buffer,
125
0
          &msg);
126
0
  if (bufel == NULL)
127
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
128
129
0
  if (type != bufel->type) {
130
0
    if (IS_DTLS(session))
131
0
      _gnutls_audit_log(
132
0
        session,
133
0
        "Discarded unexpected %s (%d) packet (expecting: %s (%d))\n",
134
0
        _gnutls_packet2str(bufel->type),
135
0
        (int)bufel->type, _gnutls_packet2str(type),
136
0
        (int)type);
137
0
    else
138
0
      _gnutls_debug_log(
139
0
        "received unexpected packet: %s(%d)\n",
140
0
        _gnutls_packet2str(bufel->type),
141
0
        (int)bufel->type);
142
143
0
    _mbuffer_head_remove_bytes(&session->internals.record_buffer,
144
0
             msg.size);
145
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
146
0
  }
147
148
0
  if (msg.size <= length)
149
0
    length = msg.size;
150
151
0
  if (seq)
152
0
    _gnutls_write_uint64(bufel->record_sequence, seq);
153
154
0
  memcpy(data, msg.data, length);
155
0
  _mbuffer_head_remove_bytes(&session->internals.record_buffer, length);
156
157
0
  return length;
158
0
}
159
160
int _gnutls_record_buffer_get_packet(content_type_t type,
161
             gnutls_session_t session,
162
             gnutls_packet_t *packet)
163
0
{
164
0
  mbuffer_st *bufel;
165
166
0
  bufel = _mbuffer_head_pop_first(&session->internals.record_buffer);
167
0
  if (bufel == NULL)
168
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
169
170
0
  if (type != bufel->type) {
171
0
    if (IS_DTLS(session))
172
0
      _gnutls_audit_log(
173
0
        session,
174
0
        "Discarded unexpected %s (%d) packet (expecting: %s)\n",
175
0
        _gnutls_packet2str(bufel->type),
176
0
        (int)bufel->type, _gnutls_packet2str(type));
177
0
    _mbuffer_head_remove_bytes(&session->internals.record_buffer,
178
0
             bufel->msg.size);
179
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
180
0
  }
181
182
0
  *packet = bufel;
183
184
0
  return bufel->msg.size - bufel->mark;
185
0
}
186
187
inline static void reset_errno(gnutls_session_t session)
188
0
{
189
0
  session->internals.errnum = 0;
190
0
}
191
192
inline static int get_errno(gnutls_session_t session, gnutls_transport_ptr_t fd)
193
0
{
194
0
  int ret;
195
196
0
  if (session->internals.errnum != 0)
197
0
    ret = session->internals.errnum;
198
0
  else
199
0
    ret = session->internals.errno_func(fd);
200
0
  return ret;
201
0
}
202
203
inline static int errno_to_gerr(int err, unsigned dtls)
204
0
{
205
0
  switch (err) {
206
0
  case EAGAIN:
207
0
    return GNUTLS_E_AGAIN;
208
0
  case EINTR:
209
0
    return GNUTLS_E_INTERRUPTED;
210
0
  case EMSGSIZE:
211
0
    if (dtls != 0)
212
0
      return GNUTLS_E_LARGE_PACKET;
213
0
    else
214
0
      return GNUTLS_E_PUSH_ERROR;
215
0
  case ECONNRESET:
216
0
    return GNUTLS_E_PREMATURE_TERMINATION;
217
0
  default:
218
0
    gnutls_assert();
219
0
    return GNUTLS_E_PUSH_ERROR;
220
0
  }
221
0
}
222
223
static ssize_t _gnutls_dgram_read(gnutls_session_t session, mbuffer_st **bufel,
224
          gnutls_pull_func pull_func, unsigned int *ms)
225
0
{
226
0
  ssize_t i, ret;
227
0
  uint8_t *ptr;
228
0
  struct timespec t1, t2;
229
0
  size_t max_size, recv_size;
230
0
  gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
231
0
  unsigned int diff;
232
233
0
  max_size = max_record_recv_size(session);
234
0
  recv_size = max_size;
235
236
0
  session->internals.direction = 0;
237
238
0
  if (ms && *ms > 0) {
239
0
    ret = _gnutls_io_check_recv(session, *ms);
240
0
    if (ret < 0)
241
0
      return gnutls_assert_val(ret);
242
0
    gnutls_gettime(&t1);
243
0
  }
244
245
0
  *bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session));
246
0
  if (*bufel == NULL)
247
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
248
249
0
  ptr = (*bufel)->msg.data;
250
251
0
  reset_errno(session);
252
0
  i = pull_func(fd, ptr, recv_size);
253
254
0
  if (i < 0) {
255
0
    int err = get_errno(session, fd);
256
257
0
    _gnutls_read_log("READ: %d returned from %p, errno=%d\n",
258
0
         (int)i, fd, err);
259
260
0
    ret = errno_to_gerr(err, 1);
261
0
    goto cleanup;
262
0
  } else {
263
0
    _gnutls_read_log("READ: Got %d bytes from %p\n", (int)i, fd);
264
0
    if (i == 0) {
265
      /* If we get here, we likely have a stream socket.
266
       * That assumption may not work on DCCP. */
267
0
      gnutls_assert();
268
0
      ret = 0;
269
0
      goto cleanup;
270
0
    }
271
272
0
    _mbuffer_set_udata_size(*bufel, i);
273
0
  }
274
275
0
  if (ms && *ms > 0) {
276
0
    gnutls_gettime(&t2);
277
0
    diff = timespec_sub_ms(&t2, &t1);
278
0
    if (diff < *ms)
279
0
      *ms -= diff;
280
0
    else {
281
0
      ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
282
0
      goto cleanup;
283
0
    }
284
0
  }
285
286
0
  _gnutls_read_log("READ: read %d bytes from %p\n", (int)i, fd);
287
288
0
  return i;
289
290
0
cleanup:
291
0
  _mbuffer_xfree(bufel);
292
0
  return ret;
293
0
}
294
295
static ssize_t _gnutls_stream_read(gnutls_session_t session, mbuffer_st **bufel,
296
           size_t size, gnutls_pull_func pull_func,
297
           unsigned int *ms)
298
0
{
299
0
  size_t left;
300
0
  ssize_t i = 0;
301
0
  size_t max_size = max_record_recv_size(session);
302
0
  uint8_t *ptr;
303
0
  gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
304
0
  int ret;
305
0
  struct timespec t1, t2;
306
0
  unsigned int diff;
307
308
0
  session->internals.direction = 0;
309
310
0
  *bufel = _mbuffer_alloc_align16(MAX(max_size, size),
311
0
          get_total_headers(session));
312
0
  if (!*bufel) {
313
0
    gnutls_assert();
314
0
    return GNUTLS_E_MEMORY_ERROR;
315
0
  }
316
0
  ptr = (*bufel)->msg.data;
317
318
0
  left = size;
319
0
  while (left > 0) {
320
0
    if (ms && *ms > 0) {
321
0
      ret = _gnutls_io_check_recv(session, *ms);
322
0
      if (ret < 0) {
323
0
        gnutls_assert();
324
0
        goto cleanup;
325
0
      }
326
327
0
      gnutls_gettime(&t1);
328
0
    }
329
330
0
    reset_errno(session);
331
332
0
    i = pull_func(fd, &ptr[size - left], left);
333
334
0
    if (i < 0) {
335
0
      int err = get_errno(session, fd);
336
337
0
      _gnutls_read_log(
338
0
        "READ: %d returned from %p, errno=%d gerrno=%d\n",
339
0
        (int)i, fd, errno, session->internals.errnum);
340
341
0
      if (err == EAGAIN || err == EINTR) {
342
0
        if (size - left > 0) {
343
0
          _gnutls_read_log(
344
0
            "READ: returning %d bytes from %p\n",
345
0
            (int)(size - left), fd);
346
347
0
          goto finish;
348
0
        }
349
350
0
        ret = errno_to_gerr(err, 0);
351
0
        goto cleanup;
352
0
      } else {
353
0
        gnutls_assert();
354
0
        ret = GNUTLS_E_PULL_ERROR;
355
0
        goto cleanup;
356
0
      }
357
0
    } else {
358
0
      _gnutls_read_log("READ: Got %d bytes from %p\n", (int)i,
359
0
           fd);
360
361
0
      if (i == 0)
362
0
        break; /* EOF */
363
0
    }
364
365
0
    left -= i;
366
0
    (*bufel)->msg.size += i;
367
368
0
    if (ms && *ms > 0 && *ms != GNUTLS_INDEFINITE_TIMEOUT) {
369
0
      gnutls_gettime(&t2);
370
0
      diff = timespec_sub_ms(&t2, &t1);
371
0
      if (diff < *ms)
372
0
        *ms -= diff;
373
0
      else {
374
0
        ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
375
0
        goto cleanup;
376
0
      }
377
0
    }
378
0
  }
379
380
0
finish:
381
382
0
  _gnutls_read_log("READ: read %d bytes from %p\n", (int)(size - left),
383
0
       fd);
384
385
0
  if (size - left == 0)
386
0
    _mbuffer_xfree(bufel);
387
388
0
  return (size - left);
389
390
0
cleanup:
391
0
  _mbuffer_xfree(bufel);
392
0
  return ret;
393
0
}
394
395
/* This function is like read. But it does not return -1 on error.
396
 * It does return gnutls_errno instead.
397
 *
398
 * Flags are only used if the default recv() function is being used.
399
 */
400
static ssize_t _gnutls_read(gnutls_session_t session, mbuffer_st **bufel,
401
          size_t size, gnutls_pull_func pull_func,
402
          unsigned int *ms)
403
0
{
404
0
  if (IS_DTLS(session))
405
    /* Size is not passed, since a whole datagram will be read. */
406
0
    return _gnutls_dgram_read(session, bufel, pull_func, ms);
407
0
  else
408
0
    return _gnutls_stream_read(session, bufel, size, pull_func, ms);
409
0
}
410
411
/* @vec: if non-zero then the vector function will be used to
412
 *       push the data.
413
 */
414
static ssize_t _gnutls_writev_emu(gnutls_session_t session,
415
          gnutls_transport_ptr_t fd,
416
          const giovec_t *giovec,
417
          unsigned int giovec_cnt, unsigned vec)
418
0
{
419
0
  unsigned int j = 0;
420
0
  size_t total = 0;
421
0
  ssize_t ret = 0;
422
423
0
  for (j = 0; j < giovec_cnt; j++) {
424
0
    if (vec) {
425
0
      ret = session->internals.vec_push_func(fd, &giovec[j],
426
0
                     1);
427
0
    } else {
428
0
      size_t sent = 0;
429
0
      ssize_t left = giovec[j].iov_len;
430
0
      char *p = giovec[j].iov_base;
431
0
      do {
432
0
        ret = session->internals.push_func(fd, p, left);
433
0
        if (ret > 0) {
434
0
          sent += ret;
435
0
          left -= ret;
436
0
          p += ret;
437
0
        }
438
0
      } while (ret > 0 && left > 0);
439
440
0
      if (sent > 0)
441
0
        ret = sent;
442
0
    }
443
444
0
    if (ret == -1) {
445
0
      gnutls_assert();
446
0
      break;
447
0
    }
448
449
0
    total += ret;
450
451
0
    if ((size_t)ret != giovec[j].iov_len)
452
0
      break;
453
0
  }
454
455
0
  if (total > 0)
456
0
    return total;
457
458
0
  return ret;
459
0
}
460
461
/* @total: The sum of the data in giovec
462
 */
463
static ssize_t _gnutls_writev(gnutls_session_t session, const giovec_t *giovec,
464
            unsigned giovec_cnt, unsigned total)
465
0
{
466
0
  int i;
467
0
  bool is_dtls = IS_DTLS(session);
468
0
  unsigned no_writev = 0;
469
0
  gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
470
471
0
  reset_errno(session);
472
473
0
  if (session->internals.vec_push_func != NULL) {
474
0
    if (is_dtls && giovec_cnt > 1) {
475
0
      if (total > session->internals.dtls.mtu) {
476
0
        no_writev = 1;
477
0
      }
478
0
    }
479
480
0
    if (no_writev == 0) {
481
0
      i = session->internals.vec_push_func(fd, giovec,
482
0
                   giovec_cnt);
483
0
    } else {
484
0
      i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt,
485
0
                 1);
486
0
    }
487
0
  } else if (session->internals.push_func != NULL) {
488
0
    i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 0);
489
0
  } else
490
0
    return gnutls_assert_val(GNUTLS_E_PUSH_ERROR);
491
492
0
  if (i == -1) {
493
0
    int err = get_errno(session, fd);
494
0
    _gnutls_debug_log("WRITE: %d returned from %p, errno: %d\n", i,
495
0
          fd, err);
496
497
0
    return errno_to_gerr(err, is_dtls);
498
0
  }
499
0
  return i;
500
0
}
501
502
/*
503
 * @ms: a pointer to the number of milliseconds to wait for data. Use zero or NULL for indefinite.
504
 *
505
 * This function is like recv(with MSG_PEEK). But it does not return -1 on error.
506
 * It does return gnutls_errno instead.
507
 * This function reads data from the socket and keeps them in a buffer, of up to
508
 * max_record_recv_size.
509
 *
510
 * This is not a general purpose function. It returns EXACTLY the data requested,
511
 * which are stored in a local (in the session) buffer.
512
 *
513
 * If the @ms parameter is non zero then this function will return before
514
 * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
515
 *
516
 */
517
ssize_t _gnutls_io_read_buffered(gnutls_session_t session, size_t total,
518
         content_type_t recv_type, unsigned int *ms)
519
0
{
520
0
  ssize_t ret;
521
0
  size_t min;
522
0
  mbuffer_st *bufel = NULL;
523
0
  size_t recvdata, readsize;
524
525
0
  if (total > max_record_recv_size(session) || total == 0) {
526
0
    gnutls_assert();
527
0
    return GNUTLS_E_RECORD_OVERFLOW;
528
0
  }
529
530
  /* calculate the actual size, ie. get the minimum of the
531
   * buffered data and the requested data.
532
   */
533
0
  min = MIN(session->internals.record_recv_buffer.byte_length, total);
534
0
  if (min > 0) {
535
    /* if we have enough buffered data
536
     * then just return them.
537
     */
538
0
    if (min == total) {
539
0
      return min;
540
0
    }
541
0
  }
542
543
  /* min is over zero. recvdata is the data we must
544
   * receive in order to return the requested data.
545
   */
546
0
  recvdata = total - min;
547
0
  readsize = recvdata;
548
549
  /* Check if the previously read data plus the new data to
550
   * receive are longer than the maximum receive buffer size.
551
   */
552
0
  if ((session->internals.record_recv_buffer.byte_length + recvdata) >
553
0
      max_record_recv_size(session)) {
554
0
    gnutls_assert(); /* internal error */
555
0
    return GNUTLS_E_INVALID_REQUEST;
556
0
  }
557
558
  /* READ DATA
559
   */
560
0
  if (readsize > 0) {
561
0
    ret = _gnutls_read(session, &bufel, readsize,
562
0
           session->internals.pull_func, ms);
563
564
    /* return immediately if we got an interrupt or eagain
565
     * error.
566
     */
567
0
    if (ret < 0) {
568
0
      return gnutls_assert_val(ret);
569
0
    }
570
571
0
    if (ret == 0) /* EOF */
572
0
      return gnutls_assert_val(0);
573
574
    /* copy fresh data to our buffer.
575
     */
576
0
    _gnutls_read_log(
577
0
      "RB: Have %d bytes into buffer. Adding %d bytes.\n",
578
0
      (int)session->internals.record_recv_buffer.byte_length,
579
0
      (int)ret);
580
0
    _gnutls_read_log("RB: Requested %d bytes\n", (int)total);
581
582
0
    _mbuffer_enqueue(&session->internals.record_recv_buffer, bufel);
583
584
0
    if (IS_DTLS(session))
585
0
      ret = MIN(total, session->internals.record_recv_buffer
586
0
             .byte_length);
587
0
    else
588
0
      ret = session->internals.record_recv_buffer.byte_length;
589
590
0
    if ((ret > 0) && ((size_t)ret < total)) /* Short Read */
591
0
      return gnutls_assert_val(GNUTLS_E_AGAIN);
592
0
    else
593
0
      return ret;
594
0
  } else
595
0
    return gnutls_assert_val(0);
596
0
}
597
598
/* This function is like write. But it does not return -1 on error.
599
 * It does return gnutls_errno instead.
600
 *
601
 * This function takes full responsibility of freeing msg->data.
602
 *
603
 * In case of E_AGAIN and E_INTERRUPTED errors, you must call
604
 * gnutls_write_flush(), until it returns ok (0).
605
 *
606
 * We need to push exactly the data in msg->size, since we cannot send
607
 * less data. In TLS the peer must receive the whole packet in order
608
 * to decrypt and verify the integrity.
609
 *
610
 */
611
ssize_t _gnutls_io_write_buffered(gnutls_session_t session, mbuffer_st *bufel,
612
          unsigned int mflag)
613
0
{
614
0
  mbuffer_head_st *const send_buffer =
615
0
    &session->internals.record_send_buffer;
616
617
  /* to know where the procedure was interrupted.
618
   */
619
0
  session->internals.direction = 1;
620
621
0
  _mbuffer_enqueue(send_buffer, bufel);
622
623
0
  _gnutls_write_log("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
624
0
        (int)bufel->msg.size,
625
0
        session->internals.transport_recv_ptr,
626
0
        (int)send_buffer->byte_length);
627
628
0
  if (mflag == MBUFFER_FLUSH)
629
0
    return _gnutls_io_write_flush(session);
630
0
  else
631
0
    return bufel->msg.size;
632
0
}
633
634
typedef ssize_t (*send_func)(gnutls_session_t, const giovec_t *, int);
635
636
/* This function writes the data that are left in the
637
 * TLS write buffer (ie. because the previous write was
638
 * interrupted.
639
 */
640
ssize_t _gnutls_io_write_flush(gnutls_session_t session)
641
0
{
642
0
  gnutls_datum_t msg;
643
0
  mbuffer_head_st *send_buffer = &session->internals.record_send_buffer;
644
0
  int ret;
645
0
  ssize_t sent = 0, tosend = 0;
646
0
  giovec_t iovec[MAX_QUEUE];
647
0
  int i = 0;
648
0
  mbuffer_st *cur;
649
650
0
  session->internals.direction = 1;
651
0
  _gnutls_write_log("WRITE FLUSH: %d bytes in buffer.\n",
652
0
        (int)send_buffer->byte_length);
653
654
0
  for (cur = _mbuffer_head_get_first(send_buffer, &msg); cur != NULL;
655
0
       cur = _mbuffer_head_get_next(cur, &msg)) {
656
0
    iovec[i].iov_base = msg.data;
657
0
    iovec[i++].iov_len = msg.size;
658
0
    tosend += msg.size;
659
660
    /* we buffer up to MAX_QUEUE messages */
661
0
    if (i >= MAX_QUEUE) {
662
0
      gnutls_assert();
663
0
      return GNUTLS_E_INTERNAL_ERROR;
664
0
    }
665
0
  }
666
667
0
  if (tosend == 0) {
668
0
    gnutls_assert();
669
0
    return 0;
670
0
  }
671
672
0
  ret = _gnutls_writev(session, iovec, i, tosend);
673
0
  if (ret >= 0) {
674
0
    _mbuffer_head_remove_bytes(send_buffer, ret);
675
0
    _gnutls_write_log("WRITE: wrote %d bytes, %d bytes left.\n",
676
0
          ret, (int)send_buffer->byte_length);
677
678
0
    sent += ret;
679
0
  } else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
680
0
    _gnutls_write_log("WRITE interrupted: %d bytes left.\n",
681
0
          (int)send_buffer->byte_length);
682
0
    return ret;
683
0
  } else if (ret == GNUTLS_E_LARGE_PACKET) {
684
0
    _mbuffer_head_remove_bytes(send_buffer, tosend);
685
0
    _gnutls_write_log(
686
0
      "WRITE cannot send large packet (%u bytes).\n",
687
0
      (unsigned int)tosend);
688
0
    return ret;
689
0
  } else {
690
0
    _gnutls_write_log("WRITE error: code %d, %d bytes left.\n", ret,
691
0
          (int)send_buffer->byte_length);
692
693
0
    gnutls_assert();
694
0
    return ret;
695
0
  }
696
697
0
  if (sent < tosend) {
698
0
    return gnutls_assert_val(GNUTLS_E_AGAIN);
699
0
  }
700
701
0
  return sent;
702
0
}
703
704
/* Checks whether there are received data within
705
 * a timeframe.
706
 *
707
 * Returns 0 if data were received, GNUTLS_E_TIMEDOUT
708
 * on timeout and a negative error code on error.
709
 */
710
int _gnutls_io_check_recv(gnutls_session_t session, unsigned int ms)
711
0
{
712
0
  gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
713
0
  int ret = 0, err;
714
715
0
  if (NO_TIMEOUT_FUNC_SET(session)) {
716
0
    _gnutls_debug_log(
717
0
      "The pull function has been replaced but not the pull timeout.\n");
718
0
    return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
719
0
  }
720
721
0
  reset_errno(session);
722
723
0
  ret = session->internals.pull_timeout_func(fd, ms);
724
0
  if (ret == -1) {
725
0
    err = get_errno(session, fd);
726
0
    _gnutls_read_log(
727
0
      "READ_TIMEOUT: %d returned from %p, errno=%d (timeout: %u)\n",
728
0
      (int)ret, fd, err, ms);
729
0
    return errno_to_gerr(err, IS_DTLS(session));
730
0
  }
731
732
0
  if (ret > 0)
733
0
    return 0;
734
0
  else
735
0
    return GNUTLS_E_TIMEDOUT;
736
0
}
737
738
/* HANDSHAKE buffers part
739
 */
740
741
/* This function writes the data that are left in the
742
 * Handshake write buffer (ie. because the previous write was
743
 * interrupted.
744
 *
745
 */
746
ssize_t _gnutls_handshake_io_write_flush(gnutls_session_t session)
747
0
{
748
0
  mbuffer_head_st *const send_buffer =
749
0
    &session->internals.handshake_send_buffer;
750
0
  gnutls_datum_t msg;
751
0
  int ret;
752
0
  uint16_t epoch;
753
0
  mbuffer_st *cur;
754
755
0
  _gnutls_write_log("HWRITE FLUSH: %d bytes in buffer.\n",
756
0
        (int)send_buffer->byte_length);
757
758
0
  if (IS_DTLS(session))
759
0
    return _dtls_transmit(session);
760
761
0
  for (cur = _mbuffer_head_get_first(send_buffer, &msg); cur != NULL;
762
0
       cur = _mbuffer_head_get_first(send_buffer, &msg)) {
763
0
    epoch = cur->epoch;
764
765
0
    if (session->internals.h_read_func) {
766
0
      record_parameters_st *params;
767
768
0
      ret = _gnutls_epoch_get(session, epoch, &params);
769
0
      if (ret < 0)
770
0
        return gnutls_assert_val(ret);
771
0
      ret = session->internals.h_read_func(
772
0
        session, params->write.level, cur->htype,
773
0
        msg.data, msg.size);
774
0
      if (ret < 0)
775
0
        return gnutls_assert_val(ret);
776
777
0
      ret = msg.size;
778
0
    } else {
779
0
      ret = _gnutls_send_int(session, cur->type, cur->htype,
780
0
                 epoch, msg.data, msg.size, 0);
781
0
    }
782
783
0
    if (ret >= 0) {
784
0
      ret = _mbuffer_head_remove_bytes(send_buffer, ret);
785
      /* for each queued message we send, ensure that
786
       * we drop the epoch refcount set in _gnutls_handshake_io_cache_int(). */
787
0
      if (ret == 1)
788
0
        _gnutls_epoch_refcount_dec(session, epoch);
789
790
0
      _gnutls_write_log(
791
0
        "HWRITE: wrote %d bytes, %d bytes left.\n", ret,
792
0
        (int)send_buffer->byte_length);
793
794
0
    } else {
795
0
      _gnutls_write_log(
796
0
        "HWRITE error: code %d, %d bytes left.\n", ret,
797
0
        (int)send_buffer->byte_length);
798
799
0
      gnutls_assert();
800
0
      return ret;
801
0
    }
802
0
  }
803
804
0
  return _gnutls_io_write_flush(session);
805
0
}
806
807
/* This is a send function for the gnutls handshake
808
 * protocol. Just makes sure that all data have been sent.
809
 *
810
 */
811
int _gnutls_handshake_io_cache_int(gnutls_session_t session,
812
           gnutls_handshake_description_t htype,
813
           mbuffer_st *bufel)
814
0
{
815
0
  mbuffer_head_st *send_buffer;
816
817
0
  if (IS_DTLS(session)) {
818
0
    bufel->handshake_sequence =
819
0
      session->internals.dtls.hsk_write_seq - 1;
820
0
  }
821
822
0
  send_buffer = &session->internals.handshake_send_buffer;
823
824
  /* ensure that our epoch does not get garbage collected
825
   * before we send all queued messages with it */
826
0
  bufel->epoch = (uint16_t)_gnutls_epoch_refcount_inc(
827
0
    session, EPOCH_WRITE_CURRENT);
828
0
  bufel->htype = htype;
829
0
  if (bufel->htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
830
0
    bufel->type = GNUTLS_CHANGE_CIPHER_SPEC;
831
0
  else
832
0
    bufel->type = GNUTLS_HANDSHAKE;
833
834
0
  _mbuffer_enqueue(send_buffer, bufel);
835
836
0
  _gnutls_write_log("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
837
0
        _gnutls_handshake2str(bufel->htype),
838
0
        (int)bufel->msg.size, (int)send_buffer->byte_length);
839
840
0
  return 0;
841
0
}
842
843
static int handshake_compare(const void *_e1, const void *_e2)
844
0
{
845
0
  const handshake_buffer_st *e1 = _e1;
846
0
  const handshake_buffer_st *e2 = _e2;
847
848
0
  if (e1->sequence <= e2->sequence)
849
0
    return 1;
850
0
  else
851
0
    return -1;
852
0
}
853
854
0
#define SSL2_HEADERS 1
855
static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
856
          handshake_buffer_st *hsk)
857
0
{
858
0
  uint8_t *dataptr = NULL; /* for realloc */
859
0
  size_t handshake_header_size = HANDSHAKE_HEADER_SIZE(session),
860
0
         data_size, frag_size;
861
862
  /* Note: SSL2_HEADERS == 1 */
863
0
  if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
864
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
865
866
0
  dataptr = _mbuffer_get_udata_ptr(bufel);
867
868
  /* if reading a client hello of SSLv2 */
869
0
#ifdef ENABLE_SSL2
870
0
  if (unlikely(!IS_DTLS(session) &&
871
0
         bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
872
0
    handshake_header_size =
873
0
      SSL2_HEADERS; /* we've already read one byte */
874
875
0
    frag_size =
876
0
      _mbuffer_get_udata_size(bufel) -
877
0
      handshake_header_size; /* we've read the first byte */
878
879
0
    if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
880
0
      return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
881
882
0
    hsk->rtype = hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
883
884
0
    hsk->sequence = 0;
885
0
    hsk->start_offset = 0;
886
0
    hsk->length = frag_size;
887
0
  } else
888
0
#endif
889
0
  { /* TLS or DTLS handshake headers */
890
891
0
    hsk->rtype = hsk->htype = dataptr[0];
892
893
    /* we do not use DECR_LEN because we know
894
     * that the packet has enough data.
895
     */
896
0
    hsk->length = _gnutls_read_uint24(&dataptr[1]);
897
898
0
    if (IS_DTLS(session)) {
899
0
      hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
900
0
      hsk->start_offset = _gnutls_read_uint24(&dataptr[6]);
901
0
      frag_size = _gnutls_read_uint24(&dataptr[9]);
902
0
    } else {
903
0
      hsk->sequence = 0;
904
0
      hsk->start_offset = 0;
905
0
      frag_size = MIN((_mbuffer_get_udata_size(bufel) -
906
0
           handshake_header_size),
907
0
          hsk->length);
908
0
    }
909
910
    /* TLS1.3: distinguish server hello versus hello retry request.
911
     * The epitome of slick protocol design. */
912
0
    if (hsk->htype == GNUTLS_HANDSHAKE_SERVER_HELLO &&
913
0
        hsk->start_offset == 0 && !IS_DTLS(session)) {
914
0
      if (_mbuffer_get_udata_size(bufel) >
915
0
            handshake_header_size + 2 +
916
0
              GNUTLS_RANDOM_SIZE &&
917
0
          memcmp(dataptr + handshake_header_size + 2,
918
0
           HRR_RANDOM, GNUTLS_RANDOM_SIZE) == 0) {
919
0
        hsk->htype =
920
0
          GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST;
921
0
      }
922
0
    }
923
0
  }
924
0
  data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
925
926
0
  if (frag_size > 0)
927
0
    hsk->end_offset = hsk->start_offset + frag_size - 1;
928
0
  else
929
0
    hsk->end_offset = 0;
930
931
0
  _gnutls_handshake_log(
932
0
    "HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
933
0
    session, _gnutls_handshake2str(hsk->htype),
934
0
    (unsigned)hsk->htype, (int)hsk->length, (int)data_size,
935
0
    hsk->start_offset, (int)frag_size, (int)hsk->sequence);
936
937
0
  hsk->header_size = handshake_header_size;
938
0
  memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
939
0
         handshake_header_size);
940
941
0
  if (hsk->length > 0 &&
942
0
      (frag_size > data_size ||
943
0
       (frag_size > 0 && hsk->end_offset >= hsk->length))) {
944
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
945
0
  } else if (hsk->length == 0 && hsk->end_offset != 0 &&
946
0
       hsk->start_offset != 0)
947
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
948
949
0
  return handshake_header_size;
950
0
}
951
952
static void _gnutls_handshake_buffer_move(handshake_buffer_st *dst,
953
            handshake_buffer_st *src)
954
0
{
955
0
  memcpy(dst, src, sizeof(*dst));
956
0
  memset(src, 0, sizeof(*src));
957
0
  src->htype = -1;
958
0
}
959
960
/* will merge the given handshake_buffer_st to the handshake_recv_buffer
961
 * list. The given hsk packet will be released in any case (success or failure).
962
 * Only used in DTLS.
963
 */
964
static int merge_handshake_packet(gnutls_session_t session,
965
          handshake_buffer_st *hsk)
966
0
{
967
0
  int exists = 0, i, pos = 0;
968
0
  int ret;
969
970
0
  for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
971
0
    if (session->internals.handshake_recv_buffer[i].htype ==
972
0
        hsk->htype) {
973
0
      exists = 1;
974
0
      pos = i;
975
0
      break;
976
0
    }
977
0
  }
978
979
0
  if (!exists)
980
0
    pos = session->internals.handshake_recv_buffer_size;
981
982
0
  if (pos >= MAX_HANDSHAKE_MSGS)
983
0
    return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
984
985
0
  if (!exists) {
986
0
    if (hsk->length != hsk->data.length) {
987
0
      ret = _gnutls_buffer_resize(&hsk->data, hsk->length);
988
0
      if (ret < 0)
989
0
        return gnutls_assert_val(ret);
990
991
0
      hsk->data.length = hsk->length;
992
0
    }
993
994
0
    if (hsk->length > 0 && hsk->end_offset > 0 &&
995
0
        hsk->end_offset - hsk->start_offset + 1 != hsk->length) {
996
0
      memmove(&hsk->data.data[hsk->start_offset],
997
0
        hsk->data.data,
998
0
        hsk->end_offset - hsk->start_offset + 1);
999
0
    }
1000
1001
0
    session->internals.handshake_recv_buffer_size++;
1002
1003
    /* rewrite headers to make them look as each packet came as a single fragment */
1004
0
    _gnutls_write_uint24(hsk->length, &hsk->header[1]);
1005
0
    _gnutls_write_uint24(0, &hsk->header[6]);
1006
0
    _gnutls_write_uint24(hsk->length, &hsk->header[9]);
1007
1008
0
    _gnutls_handshake_buffer_move(
1009
0
      &session->internals.handshake_recv_buffer[pos], hsk);
1010
1011
0
  } else {
1012
0
    if (hsk->start_offset <
1013
0
          session->internals.handshake_recv_buffer[pos]
1014
0
            .start_offset &&
1015
0
        hsk->end_offset + 1 >=
1016
0
          session->internals.handshake_recv_buffer[pos]
1017
0
            .start_offset) {
1018
0
      memcpy(&session->internals.handshake_recv_buffer[pos]
1019
0
          .data.data[hsk->start_offset],
1020
0
             hsk->data.data, hsk->data.length);
1021
0
      session->internals.handshake_recv_buffer[pos]
1022
0
        .start_offset = hsk->start_offset;
1023
0
      session->internals.handshake_recv_buffer[pos]
1024
0
        .end_offset = MIN(
1025
0
        hsk->end_offset,
1026
0
        session->internals.handshake_recv_buffer[pos]
1027
0
          .end_offset);
1028
0
    } else if (hsk->end_offset >
1029
0
           session->internals.handshake_recv_buffer[pos]
1030
0
             .end_offset &&
1031
0
         hsk->start_offset <=
1032
0
           session->internals.handshake_recv_buffer[pos]
1033
0
               .end_offset +
1034
0
             1) {
1035
0
      memcpy(&session->internals.handshake_recv_buffer[pos]
1036
0
          .data.data[hsk->start_offset],
1037
0
             hsk->data.data, hsk->data.length);
1038
1039
0
      session->internals.handshake_recv_buffer[pos]
1040
0
        .end_offset = hsk->end_offset;
1041
0
      session->internals.handshake_recv_buffer[pos]
1042
0
        .start_offset = MIN(
1043
0
        hsk->start_offset,
1044
0
        session->internals.handshake_recv_buffer[pos]
1045
0
          .start_offset);
1046
0
    }
1047
0
    _gnutls_handshake_buffer_clear(hsk);
1048
0
  }
1049
1050
0
  return 0;
1051
0
}
1052
1053
/* returns non-zero on match and zero on mismatch
1054
 */
1055
inline static int cmp_hsk_types(gnutls_handshake_description_t expected,
1056
        gnutls_handshake_description_t recvd)
1057
0
{
1058
0
  if (expected == GNUTLS_HANDSHAKE_ANY)
1059
0
    return 1;
1060
1061
0
#ifdef ENABLE_SSL2
1062
0
  if (expected == GNUTLS_HANDSHAKE_CLIENT_HELLO &&
1063
0
      recvd == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)
1064
0
    return 1;
1065
0
#endif
1066
0
  if (expected != recvd)
1067
0
    return 0;
1068
1069
0
  return 1;
1070
0
}
1071
1072
0
#define LAST_ELEMENT (session->internals.handshake_recv_buffer_size - 1)
1073
1074
/* returns the last stored handshake packet.
1075
 */
1076
static int get_last_packet(gnutls_session_t session,
1077
         gnutls_handshake_description_t htype,
1078
         handshake_buffer_st *hsk, unsigned int optional)
1079
0
{
1080
0
  handshake_buffer_st *recv_buf =
1081
0
    session->internals.handshake_recv_buffer;
1082
1083
0
  if (IS_DTLS(session)) {
1084
0
    if (session->internals.handshake_recv_buffer_size == 0 ||
1085
0
        (session->internals.dtls.hsk_read_seq !=
1086
0
         recv_buf[LAST_ELEMENT].sequence))
1087
0
      goto timeout;
1088
1089
0
    if (htype != recv_buf[LAST_ELEMENT].htype) {
1090
0
      if (optional == 0)
1091
0
        _gnutls_audit_log(
1092
0
          session,
1093
0
          "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
1094
0
          _gnutls_handshake2str(
1095
0
            recv_buf[0].htype),
1096
0
          (int)recv_buf[0].htype,
1097
0
          _gnutls_handshake2str(htype),
1098
0
          (int)htype);
1099
1100
0
      return gnutls_assert_val(
1101
0
        GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
1102
0
    }
1103
1104
0
    else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
1105
0
        recv_buf[LAST_ELEMENT].end_offset ==
1106
0
          recv_buf[LAST_ELEMENT].length - 1) ||
1107
0
       recv_buf[LAST_ELEMENT].length == 0) {
1108
0
      session->internals.dtls.hsk_read_seq++;
1109
0
      _gnutls_handshake_buffer_move(hsk,
1110
0
                  &recv_buf[LAST_ELEMENT]);
1111
0
      session->internals.handshake_recv_buffer_size--;
1112
0
      return 0;
1113
0
    } else {
1114
      /* if we don't have a complete handshake message, but we
1115
       * have queued data waiting, try again to reconstruct the
1116
       * handshake packet, using the queued */
1117
0
      if (recv_buf[LAST_ELEMENT].end_offset !=
1118
0
            recv_buf[LAST_ELEMENT].length - 1 &&
1119
0
          record_check_unprocessed(session) > 0)
1120
0
        return gnutls_assert_val(
1121
0
          GNUTLS_E_INT_CHECK_AGAIN);
1122
0
      else
1123
0
        goto timeout;
1124
0
    }
1125
0
  } else { /* TLS */
1126
1127
0
    if (session->internals.handshake_recv_buffer_size > 0 &&
1128
0
        recv_buf[0].length == recv_buf[0].data.length) {
1129
0
      if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) {
1130
0
        return gnutls_assert_val(
1131
0
          GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
1132
0
      }
1133
1134
0
      _gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
1135
0
      session->internals.handshake_recv_buffer_size--;
1136
0
      return 0;
1137
0
    } else
1138
0
      return gnutls_assert_val(
1139
0
        GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1140
0
  }
1141
1142
0
timeout:
1143
0
  RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
1144
0
}
1145
1146
/* This is a receive function for the gnutls handshake
1147
 * protocol. Makes sure that we have received all data.
1148
 *
1149
 * htype is the next handshake packet expected.
1150
 */
1151
int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
1152
0
{
1153
0
  gnutls_datum_t msg;
1154
0
  mbuffer_st *bufel = NULL, *prev = NULL;
1155
0
  int ret;
1156
0
  size_t data_size;
1157
0
  handshake_buffer_st *recv_buf =
1158
0
    session->internals.handshake_recv_buffer;
1159
1160
0
  bufel = _mbuffer_head_get_first(&session->internals.record_buffer,
1161
0
          &msg);
1162
0
  if (bufel == NULL)
1163
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1164
1165
0
  if (!IS_DTLS(session)) {
1166
0
    ssize_t append, header_size;
1167
1168
0
    do {
1169
0
      if (bufel->type != GNUTLS_HANDSHAKE)
1170
0
        return gnutls_assert_val(
1171
0
          GNUTLS_E_UNEXPECTED_PACKET);
1172
1173
0
      if (unlikely(
1174
0
            session->internals
1175
0
                .handshake_recv_buffer_size ==
1176
0
              0 &&
1177
0
            msg.size < HANDSHAKE_HEADER_SIZE(session) &&
1178
0
            session->internals
1179
0
                .handshake_header_recv_buffer
1180
0
                .byte_length <
1181
0
              HANDSHAKE_HEADER_SIZE(session) -
1182
0
                msg.size)) {
1183
0
        bufel = _mbuffer_head_pop_first(
1184
0
          &session->internals.record_buffer);
1185
0
        _mbuffer_enqueue(
1186
0
          &session->internals
1187
0
             .handshake_header_recv_buffer,
1188
0
          bufel);
1189
0
        break;
1190
0
      } else if (session->internals.handshake_recv_buffer_size >
1191
0
             0 &&
1192
0
           recv_buf[0].length >
1193
0
             recv_buf[0].data.length) {
1194
        /* this is the rest of a previous message */
1195
0
        append = MIN(msg.size,
1196
0
               recv_buf[0].length -
1197
0
                 recv_buf[0].data.length);
1198
1199
0
        ret = _gnutls_buffer_append_data(
1200
0
          &recv_buf[0].data, msg.data, append);
1201
0
        if (ret < 0)
1202
0
          return gnutls_assert_val(ret);
1203
1204
0
        _mbuffer_head_remove_bytes(
1205
0
          &session->internals.record_buffer,
1206
0
          append);
1207
0
      } else { /* received new message */
1208
0
        if (unlikely(
1209
0
              session->internals
1210
0
                .handshake_header_recv_buffer
1211
0
                .length > 0)) {
1212
0
          bufel = _mbuffer_head_pop_first(
1213
0
            &session->internals
1214
0
               .record_buffer);
1215
0
          _mbuffer_enqueue(
1216
0
            &session->internals
1217
0
               .handshake_header_recv_buffer,
1218
0
            bufel);
1219
0
          ret = _mbuffer_linearize_align16(
1220
0
            &session->internals
1221
0
               .handshake_header_recv_buffer,
1222
0
            get_total_headers(session));
1223
0
          if (ret < 0)
1224
0
            return gnutls_assert_val(ret);
1225
0
          bufel = _mbuffer_head_pop_first(
1226
0
            &session->internals
1227
0
               .handshake_header_recv_buffer);
1228
0
          _mbuffer_head_push_first(
1229
0
            &session->internals
1230
0
               .record_buffer,
1231
0
            bufel);
1232
0
        }
1233
1234
0
        ret = parse_handshake_header(session, bufel,
1235
0
                   &recv_buf[0]);
1236
0
        if (ret < 0)
1237
0
          return gnutls_assert_val(ret);
1238
1239
0
        header_size = ret;
1240
0
        session->internals.handshake_recv_buffer_size =
1241
0
          1;
1242
1243
0
        _mbuffer_set_uhead_size(bufel, header_size);
1244
1245
0
        data_size = MIN(recv_buf[0].length,
1246
0
            _mbuffer_get_udata_size(bufel));
1247
0
        ret = _gnutls_buffer_append_data(
1248
0
          &recv_buf[0].data,
1249
0
          _mbuffer_get_udata_ptr(bufel),
1250
0
          data_size);
1251
0
        if (ret < 0)
1252
0
          return gnutls_assert_val(ret);
1253
0
        _mbuffer_set_uhead_size(bufel, 0);
1254
0
        _mbuffer_head_remove_bytes(
1255
0
          &session->internals.record_buffer,
1256
0
          data_size + header_size);
1257
0
      }
1258
1259
      /* if packet is complete then return it
1260
       */
1261
0
      if (recv_buf[0].length == recv_buf[0].data.length) {
1262
0
        return 0;
1263
0
      }
1264
0
      bufel = _mbuffer_head_get_first(
1265
0
        &session->internals.record_buffer, &msg);
1266
0
    } while (bufel != NULL);
1267
1268
    /* if we are here it means that the received packets were not
1269
     * enough to complete the handshake packet.
1270
     */
1271
0
    return gnutls_assert_val(GNUTLS_E_AGAIN);
1272
0
  } else { /* DTLS */
1273
1274
0
    handshake_buffer_st tmp;
1275
1276
0
    do {
1277
      /* we now
1278
       * 0. parse headers
1279
       * 1. insert to handshake_recv_buffer
1280
       * 2. sort handshake_recv_buffer on sequence numbers
1281
       * 3. return first packet if completed or GNUTLS_E_AGAIN.
1282
       */
1283
0
      do {
1284
0
        if (bufel->type != GNUTLS_HANDSHAKE) {
1285
0
          gnutls_assert();
1286
0
          goto next; /* ignore packet */
1287
0
        }
1288
1289
0
        _gnutls_handshake_buffer_init(&tmp);
1290
1291
0
        ret = parse_handshake_header(session, bufel,
1292
0
                   &tmp);
1293
0
        if (ret < 0) {
1294
0
          gnutls_assert();
1295
0
          _gnutls_audit_log(
1296
0
            session,
1297
0
            "Invalid handshake packet headers. Discarding.\n");
1298
0
          break;
1299
0
        }
1300
1301
0
        _mbuffer_consume(
1302
0
          &session->internals.record_buffer,
1303
0
          bufel, ret);
1304
1305
0
        data_size = MIN(tmp.length,
1306
0
            tmp.end_offset -
1307
0
              tmp.start_offset + 1);
1308
1309
0
        ret = _gnutls_buffer_append_data(
1310
0
          &tmp.data,
1311
0
          _mbuffer_get_udata_ptr(bufel),
1312
0
          data_size);
1313
0
        if (ret < 0)
1314
0
          return gnutls_assert_val(ret);
1315
1316
0
        _mbuffer_consume(
1317
0
          &session->internals.record_buffer,
1318
0
          bufel, data_size);
1319
1320
0
        ret = merge_handshake_packet(session, &tmp);
1321
0
        if (ret < 0)
1322
0
          return gnutls_assert_val(ret);
1323
1324
0
      } while (_mbuffer_get_udata_size(bufel) > 0);
1325
1326
0
      prev = bufel;
1327
0
      bufel = _mbuffer_dequeue(
1328
0
        &session->internals.record_buffer, bufel);
1329
1330
0
      _mbuffer_xfree(&prev);
1331
0
      continue;
1332
1333
0
    next:
1334
0
      bufel = _mbuffer_head_get_next(bufel, NULL);
1335
0
    } while (bufel != NULL);
1336
1337
    /* sort in descending order */
1338
0
    if (session->internals.handshake_recv_buffer_size > 1)
1339
0
      qsort(recv_buf,
1340
0
            session->internals.handshake_recv_buffer_size,
1341
0
            sizeof(recv_buf[0]), handshake_compare);
1342
1343
0
    while (session->internals.handshake_recv_buffer_size > 0 &&
1344
0
           recv_buf[LAST_ELEMENT].sequence <
1345
0
             session->internals.dtls.hsk_read_seq) {
1346
0
      _gnutls_audit_log(
1347
0
        session,
1348
0
        "Discarded replayed handshake packet with sequence %d\n",
1349
0
        recv_buf[LAST_ELEMENT].sequence);
1350
0
      _gnutls_handshake_buffer_clear(&recv_buf[LAST_ELEMENT]);
1351
0
      session->internals.handshake_recv_buffer_size--;
1352
0
    }
1353
1354
0
    return 0;
1355
0
  }
1356
0
}
1357
1358
/* This is a receive function for the gnutls handshake
1359
 * protocol. Makes sure that we have received all data.
1360
 */
1361
ssize_t _gnutls_handshake_io_recv_int(gnutls_session_t session,
1362
              gnutls_handshake_description_t htype,
1363
              handshake_buffer_st *hsk,
1364
              unsigned int optional)
1365
0
{
1366
0
  int ret;
1367
0
  unsigned int tleft = 0;
1368
0
  int retries = 7;
1369
1370
0
  ret = get_last_packet(session, htype, hsk, optional);
1371
0
  if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED &&
1372
0
      ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE &&
1373
0
      ret != GNUTLS_E_INT_CHECK_AGAIN) {
1374
0
    return gnutls_assert_val(ret);
1375
0
  }
1376
1377
  /* try using the already existing records before
1378
   * trying to receive.
1379
   */
1380
0
  ret = _gnutls_parse_record_buffered_msgs(session);
1381
1382
0
  if (ret == 0) {
1383
0
    ret = get_last_packet(session, htype, hsk, optional);
1384
0
  }
1385
1386
0
  if (IS_DTLS(session)) {
1387
0
    if (ret >= 0)
1388
0
      return ret;
1389
0
  } else {
1390
0
    if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && ret < 0) ||
1391
0
        ret >= 0)
1392
0
      return gnutls_assert_val(ret);
1393
0
  }
1394
1395
  /* If handshake is handled manually, don't receive records from I/O */
1396
0
  if (session->internals.h_read_func)
1397
0
    return GNUTLS_E_AGAIN;
1398
1399
0
  if (htype != (gnutls_handshake_description_t)-1) {
1400
0
    ret = handshake_remaining_time(session);
1401
0
    if (ret < 0)
1402
0
      return gnutls_assert_val(ret);
1403
0
    tleft = ret;
1404
0
  }
1405
1406
0
  do {
1407
    /* if we don't have a complete message waiting for us, try
1408
     * receiving more */
1409
0
    ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
1410
0
                tleft);
1411
0
    if (ret < 0)
1412
0
      return gnutls_assert_val_fatal(ret);
1413
1414
0
    ret = _gnutls_parse_record_buffered_msgs(session);
1415
0
    if (ret == 0) {
1416
0
      ret = get_last_packet(session, htype, hsk, optional);
1417
0
    }
1418
    /* we put an upper limit (retries) to the number of partial handshake
1419
     * messages in a record packet. */
1420
0
  } while (IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN &&
1421
0
     retries-- > 0);
1422
1423
0
  if (unlikely(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN)) {
1424
0
    ret = gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
1425
0
  }
1426
1427
0
  return ret;
1428
0
}