Coverage Report

Created: 2023-03-26 07:33

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