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