2 * Copyright (C) 2009-2012 Free Software Foundation, Inc.
4 * Authors: Jonathan Bastien-Filiatrault
5 * Nikos Mavrogiannopoulos
7 * This file is part of GNUTLS.
9 * The GNUTLS library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 3 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
24 /* Functions that relate to DTLS retransmission and reassembly.
27 #include "gnutls_int.h"
28 #include "gnutls_errors.h"
30 #include "gnutls_dtls.h"
31 #include "gnutls_record.h"
32 #include <gnutls_mbuffers.h>
33 #include <gnutls_buffers.h>
34 #include <gnutls_constate.h>
35 #include <gnutls_state.h>
36 #include <gnutls/dtls.h>
39 /* returns a-b in ms */
41 _dtls_timespec_sub_ms (struct timespec
*a
, struct timespec
*b
)
43 return (a
->tv_sec
* 1000 + a
->tv_nsec
/ (1000 * 1000) -
44 (b
->tv_sec
* 1000 + b
->tv_nsec
/ (1000 * 1000)));
48 _dtls_async_timer_delete (gnutls_session_t session
)
50 if (session
->internals
.dtls
.async_term
!= 0)
52 _gnutls_dtls_log ("DTLS[%p]: Deinitializing previous handshake state.\n", session
);
53 session
->internals
.dtls
.async_term
= 0; /* turn off "timer" */
55 _dtls_reset_hsk_state(session
);
56 _gnutls_handshake_io_buffer_clear (session
);
57 _gnutls_epoch_gc(session
);
61 /* This function fragments and transmits a previously buffered
62 * outgoing message. It accepts mtu_data which is a buffer to
63 * be reused (should be set to NULL initially).
66 transmit_message (gnutls_session_t session
,
67 mbuffer_st
*bufel
, uint8_t **buf
)
69 uint8_t *data
, *mtu_data
;
71 unsigned int offset
, frag_len
, data_size
;
72 const unsigned int mtu
= gnutls_dtls_get_data_mtu(session
) - DTLS_HANDSHAKE_HEADER_SIZE
;
74 if (bufel
->type
== GNUTLS_CHANGE_CIPHER_SPEC
)
76 _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d)\n",
77 session
, bufel
->handshake_sequence
,
78 _gnutls_handshake2str (bufel
->htype
),
81 return _gnutls_send_int (session
, bufel
->type
, -1,
83 _mbuffer_get_uhead_ptr(bufel
),
84 _mbuffer_get_uhead_size(bufel
), 0);
87 if (*buf
== NULL
) *buf
= gnutls_malloc(mtu
+ DTLS_HANDSHAKE_HEADER_SIZE
);
89 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
93 data
= _mbuffer_get_udata_ptr( bufel
);
94 data_size
= _mbuffer_get_udata_size(bufel
);
96 /* Write fixed headers
100 mtu_data
[0] = (uint8_t) bufel
->htype
;
103 _gnutls_write_uint24 (data_size
, &mtu_data
[1]);
105 /* Handshake sequence */
106 _gnutls_write_uint16 (bufel
->handshake_sequence
, &mtu_data
[4]);
108 /* Chop up and send handshake message into mtu-size pieces. */
109 for (offset
=0; offset
<= data_size
; offset
+= mtu
)
111 /* Calculate fragment length */
112 if(offset
+ mtu
> data_size
)
113 frag_len
= data_size
- offset
;
117 /* Fragment offset */
118 _gnutls_write_uint24 (offset
, &mtu_data
[6]);
120 /* Fragment length */
121 _gnutls_write_uint24 (frag_len
, &mtu_data
[9]);
123 memcpy (&mtu_data
[DTLS_HANDSHAKE_HEADER_SIZE
], data
+offset
, frag_len
);
125 _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
126 "length: %u, offset: %u, fragment length: %u\n",
127 session
, bufel
->handshake_sequence
,
128 _gnutls_handshake2str (bufel
->htype
),
129 bufel
->htype
, data_size
, offset
, frag_len
);
131 ret
= _gnutls_send_int (session
, bufel
->type
, bufel
->htype
,
132 bufel
->epoch
, mtu_data
, DTLS_HANDSHAKE_HEADER_SIZE
+ frag_len
, 0);
143 static int drop_usage_count(gnutls_session_t session
, mbuffer_head_st
*const send_buffer
)
148 for (cur
= send_buffer
->head
;
149 cur
!= NULL
; cur
= cur
->next
)
151 ret
= _gnutls_epoch_refcount_dec(session
, cur
->epoch
);
153 return gnutls_assert_val(ret
);
159 /* This function is to be called from record layer once
160 * a handshake replay is detected. It will make sure
161 * it transmits only once per few seconds. Otherwise
162 * it is the same as _dtls_transmit().
164 int _dtls_retransmit(gnutls_session_t session
)
166 return _dtls_transmit(session
);
169 /* Checks whether the received packet contains a handshake
170 * packet with sequence higher that the previously received.
171 * It must be called only when an actual packet has been
174 * Returns: 0 if expected, negative value otherwise.
176 static int is_next_hpacket_expected(gnutls_session_t session
)
180 /* htype is arbitrary */
181 ret
= _gnutls_recv_in_buffers(session
, GNUTLS_HANDSHAKE
, GNUTLS_HANDSHAKE_FINISHED
);
183 return gnutls_assert_val(ret
);
185 ret
= _gnutls_parse_record_buffered_msgs(session
);
187 return gnutls_assert_val(ret
);
189 if (session
->internals
.handshake_recv_buffer_size
> 0)
192 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
);
195 void _dtls_reset_hsk_state(gnutls_session_t session
)
197 session
->internals
.dtls
.flight_init
= 0;
198 drop_usage_count(session
, &session
->internals
.handshake_send_buffer
);
199 _mbuffer_head_clear(&session
->internals
.handshake_send_buffer
);
203 #define UPDATE_TIMER { \
204 session->internals.dtls.actual_retrans_timeout_ms *= 2; \
205 session->internals.dtls.actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT; \
208 #define RESET_TIMER \
209 session->internals.dtls.actual_retrans_timeout_ms = session->internals.dtls.retrans_timeout_ms
211 #define TIMER_WINDOW session->internals.dtls.actual_retrans_timeout_ms
213 /* This function transmits the flight that has been previously
216 * This function is called from the handshake layer and calls the
220 _dtls_transmit (gnutls_session_t session
)
224 unsigned int timeout
;
226 /* PREPARING -> SENDING state transition */
227 mbuffer_head_st
*const send_buffer
=
228 &session
->internals
.handshake_send_buffer
;
230 gnutls_handshake_description_t last_type
= 0;
236 /* If we have already sent a flight and we are operating in a
237 * non blocking way, check if it is time to retransmit or just
240 if (session
->internals
.dtls
.flight_init
!= 0 && session
->internals
.dtls
.blocking
== 0)
242 /* just in case previous run was interrupted */
243 ret
= _gnutls_io_write_flush (session
);
250 if (session
->internals
.dtls
.last_flight
== 0 || !_dtls_is_async(session
))
253 ret
= _gnutls_io_check_recv(session
, 0);
254 if (ret
== GNUTLS_E_TIMEDOUT
)
256 /* if no retransmission is required yet just return
258 if (_dtls_timespec_sub_ms(&now
, &session
->internals
.dtls
.last_retransmit
) < TIMER_WINDOW
)
264 else /* received something */
268 ret
= is_next_hpacket_expected(session
);
269 if (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
)
271 if (ret
< 0 && ret
!= GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
)
276 if (ret
== 0) goto end_flight
;
277 /* if ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET retransmit */
287 timeout
= TIMER_WINDOW
;
289 diff
= _dtls_timespec_sub_ms(&now
, &session
->internals
.dtls
.handshake_start_time
);
290 if (diff
>= session
->internals
.dtls
.total_timeout_ms
)
292 _gnutls_dtls_log("Session timeout: %u ms\n", diff
);
293 ret
= gnutls_assert_val(GNUTLS_E_TIMEDOUT
);
297 diff
= _dtls_timespec_sub_ms(&now
, &session
->internals
.dtls
.last_retransmit
);
298 if (session
->internals
.dtls
.flight_init
== 0 || diff
>= TIMER_WINDOW
)
300 _gnutls_dtls_log ("DTLS[%p]: %sStart of flight transmission.\n", session
, (session
->internals
.dtls
.flight_init
== 0)?"":"re-");
301 for (cur
= send_buffer
->head
;
302 cur
!= NULL
; cur
= cur
->next
)
304 ret
= transmit_message (session
, cur
, &buf
);
311 last_type
= cur
->htype
;
313 gettime(&session
->internals
.dtls
.last_retransmit
);
315 if (session
->internals
.dtls
.flight_init
== 0)
317 session
->internals
.dtls
.flight_init
= 1;
319 timeout
= TIMER_WINDOW
;
321 if (last_type
== GNUTLS_HANDSHAKE_FINISHED
)
323 /* On the last flight we cannot ensure retransmission
324 * from here. _dtls_wait_and_retransmit() is being called
327 session
->internals
.dtls
.last_flight
= 1;
330 session
->internals
.dtls
.last_flight
= 0;
338 ret
= _gnutls_io_write_flush (session
);
341 ret
= gnutls_assert_val(ret
);
345 /* last message in handshake -> no ack */
346 if (session
->internals
.dtls
.last_flight
!= 0)
348 /* we don't wait here. We just return 0 and
349 * if a retransmission occurs because peer didn't receive it
350 * we rely on the record or handshake
351 * layer calling this function again.
356 else /* all other messages -> implicit ack (receive of next flight) */
358 if (session
->internals
.dtls
.blocking
!= 0)
359 ret
= _gnutls_io_check_recv(session
, timeout
);
362 ret
= _gnutls_io_check_recv(session
, 0);
363 if (ret
== GNUTLS_E_TIMEDOUT
)
371 ret
= is_next_hpacket_expected(session
);
372 if (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
)
375 if (ret
== GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
)
377 ret
= GNUTLS_E_TIMEDOUT
;
391 } while(ret
== GNUTLS_E_TIMEDOUT
);
395 ret
= gnutls_assert_val(ret
);
402 _gnutls_dtls_log ("DTLS[%p]: End of flight transmission.\n", session
);
403 _dtls_reset_hsk_state(session
);
409 /* SENDING -> WAITING state transition */
416 RETURN_DTLS_EAGAIN_OR_TIMEOUT(session
, ret
);
419 /* Waits for the last flight or retransmits
420 * the previous on timeout. Returns 0 on success.
422 int _dtls_wait_and_retransmit(gnutls_session_t session
)
426 if (session
->internals
.dtls
.blocking
!= 0)
427 ret
= _gnutls_io_check_recv(session
, TIMER_WINDOW
);
429 ret
= _gnutls_io_check_recv(session
, 0);
431 if (ret
== GNUTLS_E_TIMEDOUT
)
433 ret
= _dtls_retransmit(session
);
436 RETURN_DTLS_EAGAIN_OR_TIMEOUT(session
, 0);
439 return gnutls_assert_val(ret
);
447 #define window_table rp->record_sw
448 #define window_size rp->record_sw_size
450 /* FIXME: could we modify that code to avoid using
454 static void rot_window(struct record_parameters_st
* rp
, int places
)
456 window_size
-= places
;
457 memmove(window_table
, &window_table
[places
], window_size
*sizeof(window_table
[0]));
461 /* Checks if a sequence number is not replayed. If replayed
462 * returns a negative error code, otherwise zero.
464 int _dtls_record_check(struct record_parameters_st
*rp
, uint64
* _seq
)
466 uint64_t seq
= 0, diff
;
467 unsigned int i
, offset
= 0;
472 seq
|= _seq
->i
[i
] & 0xff;
475 if (window_size
== 0)
478 window_table
[0] = seq
;
482 if (seq
<= window_table
[0])
487 if (window_size
== DTLS_RECORD_WINDOW_SIZE
)
489 rot_window(rp
, MOVE_SIZE
);
492 if (seq
< window_table
[window_size
-1])
494 /* is between first and last */
495 diff
= window_table
[window_size
-1] - seq
;
497 if (diff
>= window_size
)
500 offset
= window_size
-1-diff
;
502 if (window_table
[offset
] == seq
)
505 window_table
[offset
] = seq
;
507 else /* seq >= last */
509 if (seq
== window_table
[window_size
-1])
514 diff
= seq
- window_table
[window_size
-1];
515 if (diff
<= DTLS_RECORD_WINDOW_SIZE
- window_size
)
516 { /* fits in our empty space */
517 offset
= diff
+ window_size
-1;
519 window_table
[offset
] = seq
;
520 window_size
= offset
+ 1;
524 if (diff
> DTLS_RECORD_WINDOW_SIZE
/2)
525 { /* difference is too big */
526 window_table
[DTLS_RECORD_WINDOW_SIZE
-1] = seq
;
527 window_size
= DTLS_RECORD_WINDOW_SIZE
;
531 rot_window(rp
, diff
);
532 offset
= diff
+ window_size
-1;
533 window_table
[offset
] = seq
;
534 window_size
= offset
+ 1;
543 * gnutls_dtls_set_timeouts:
544 * @session: is a #gnutls_session_t structure.
545 * @retrans_timeout: The time at which a retransmission will occur in milliseconds
546 * @total_timeout: The time at which the connection will be aborted, in milliseconds.
548 * This function will set the timeouts required for the DTLS handshake
549 * protocol. The retransmission timeout is the time after which a
550 * message from the peer is not received, the previous messages will
551 * be retransmitted. The total timeout is the time after which the
552 * handshake will be aborted with %GNUTLS_E_TIMEDOUT.
554 * The DTLS protocol recommends the values of 1 sec and 60 seconds
557 * If the retransmission timeout is zero then the handshake will operate
558 * in a non-blocking way, i.e., return %GNUTLS_E_AGAIN.
562 void gnutls_dtls_set_timeouts (gnutls_session_t session
, unsigned int retrans_timeout
,
563 unsigned int total_timeout
)
565 session
->internals
.dtls
.retrans_timeout_ms
= retrans_timeout
;
566 session
->internals
.dtls
.total_timeout_ms
= total_timeout
;
570 * gnutls_dtls_set_mtu:
571 * @session: is a #gnutls_session_t structure.
572 * @mtu: The maximum transfer unit of the interface
574 * This function will set the maximum transfer unit of the interface
575 * that DTLS packets are expected to leave from.
579 void gnutls_dtls_set_mtu (gnutls_session_t session
, unsigned int mtu
)
581 session
->internals
.dtls
.mtu
= mtu
;
584 /* returns overhead imposed by the record layer (encryption/compression)
585 * etc. It does not include the record layer headers, since the caller
586 * needs to cope with rounding to multiples of blocksize, and the header
589 * blocksize: will contain the block size when padding may be required or 1
591 * It may return a negative error code on error.
593 static int _gnutls_record_overhead_rt(gnutls_session_t session
, unsigned int *blocksize
)
595 record_parameters_st
*params
;
596 int total
= 0, ret
, iv_size
;
598 if (session
->internals
.initial_negotiation_completed
== 0)
599 return GNUTLS_E_INVALID_REQUEST
;
601 ret
= _gnutls_epoch_get (session
, EPOCH_WRITE_CURRENT
, ¶ms
);
603 return gnutls_assert_val(ret
);
605 /* requires padding */
606 iv_size
= _gnutls_cipher_get_iv_size(params
->cipher_algorithm
);
608 if (_gnutls_cipher_is_block (params
->cipher_algorithm
) == CIPHER_BLOCK
)
610 *blocksize
= iv_size
;
612 if (!IS_DTLS(session
))
613 total
+= MAX_PAD_SIZE
;
615 total
+= iv_size
; /* iv_size == block_size */
622 if (params
->mac_algorithm
== GNUTLS_MAC_AEAD
)
623 total
+= _gnutls_cipher_get_tag_size(params
->cipher_algorithm
);
626 ret
= _gnutls_hmac_get_algo_len(params
->mac_algorithm
);
628 return gnutls_assert_val(ret
);
632 if (params
->compression_algorithm
!= GNUTLS_COMP_NULL
)
633 total
+= EXTRA_COMP_SIZE
;
635 /* We always pad with at least one byte; never 0. */
642 * gnutls_dtls_get_data_mtu:
643 * @session: is a #gnutls_session_t structure.
645 * This function will return the actual maximum transfer unit for
646 * application data. I.e. DTLS headers are subtracted from the
649 * Returns: the maximum allowed transfer unit.
653 unsigned int gnutls_dtls_get_data_mtu (gnutls_session_t session
)
655 int mtu
= session
->internals
.dtls
.mtu
;
659 mtu
-= RECORD_HEADER_SIZE(session
);
661 overhead
= _gnutls_record_overhead_rt(session
, &blocksize
);
666 mtu
-= mtu
% blocksize
;
668 return mtu
- overhead
;
672 * gnutls_dtls_get_mtu:
673 * @session: is a #gnutls_session_t structure.
675 * This function will return the MTU size as set with
676 * gnutls_dtls_set_mtu(). This is not the actual MTU
677 * of data you can transmit. Use gnutls_dtls_get_data_mtu()
680 * Returns: the set maximum transfer unit.
684 unsigned int gnutls_dtls_get_mtu (gnutls_session_t session
)
686 return session
->internals
.dtls
.mtu
;
690 * gnutls_dtls_get_timeout:
691 * @session: is a #gnutls_session_t structure.
693 * This function will return the milliseconds remaining
694 * for a retransmission of the previously sent handshake
695 * message. This function is useful when DTLS is used in
696 * non-blocking mode, to estimate when to call gnutls_handshake()
697 * if no packets have been received.
699 * Returns: the remaining time in milliseconds.
703 unsigned int gnutls_dtls_get_timeout (gnutls_session_t session
)
710 diff
= _dtls_timespec_sub_ms(&now
, &session
->internals
.dtls
.last_retransmit
);
711 if (diff
>= TIMER_WINDOW
)
714 return TIMER_WINDOW
- diff
;
717 #define COOKIE_SIZE 16
718 #define COOKIE_MAC_SIZE 16
726 #define C_HASH GNUTLS_MAC_SHA1
727 #define C_HASH_SIZE 20
730 * gnutls_dtls_cookie_send:
731 * @key: is a random key to be used at cookie generation
732 * @client_data: contains data identifying the client (i.e. address)
733 * @client_data_size: The size of client's data
734 * @prestate: The previous cookie returned by gnutls_dtls_cookie_verify()
735 * @ptr: A transport pointer to be used by @push_func
736 * @push_func: A function that will be used to reply
738 * This function can be used to prevent denial of service
739 * attacks to a DTLS server by requiring the client to
740 * reply using a cookie sent by this function. That way
741 * it can be ensured that a client we allocated resources
742 * for (i.e. #gnutls_session_t) is the one that the
743 * original incoming packet was originated from.
745 * Returns: the number of bytes sent, or a negative error code.
749 int gnutls_dtls_cookie_send(gnutls_datum_t
* key
, void* client_data
, size_t client_data_size
,
750 gnutls_dtls_prestate_st
* prestate
,
751 gnutls_transport_ptr_t ptr
, gnutls_push_func push_func
)
753 uint8_t hvr
[20+DTLS_HANDSHAKE_HEADER_SIZE
+COOKIE_SIZE
];
754 int hvr_size
= 0, ret
;
755 uint8_t digest
[C_HASH_SIZE
];
757 if (key
== NULL
|| key
->data
== NULL
|| key
->size
== 0)
758 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
762 * ContentType type - 1 byte GNUTLS_HANDSHAKE;
763 * ProtocolVersion version; - 2 bytes (254,255)
764 * uint16 epoch; - 2 bytes (0, 0)
765 * uint48 sequence_number; - 4 bytes (0,0,0,0)
766 * uint16 length; - 2 bytes (COOKIE_SIZE+1+2)+DTLS_HANDSHAKE_HEADER_SIZE
767 * uint8_t fragment[DTLSPlaintext.length];
772 * HandshakeType msg_type; 1 byte - GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST
773 * uint24 length; - COOKIE_SIZE+3
774 * uint16 message_seq; - 2 bytes (0,0)
775 * uint24 fragment_offset; - 3 bytes (0,0,0)
776 * uint24 fragment_length; - same as length
780 * ProtocolVersion server_version;
781 * uint8_t cookie<0..32>;
782 * } HelloVerifyRequest;
785 hvr
[hvr_size
++] = GNUTLS_HANDSHAKE
;
787 hvr
[hvr_size
++] = 254;
788 hvr
[hvr_size
++] = 255;
791 memset(&hvr
[hvr_size
], 0, 8);
793 hvr
[hvr_size
++] = prestate
->record_seq
;
796 _gnutls_write_uint16(DTLS_HANDSHAKE_HEADER_SIZE
+COOKIE_SIZE
+3, &hvr
[hvr_size
]);
799 /* now handshake headers */
800 hvr
[hvr_size
++] = GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST
;
801 _gnutls_write_uint24(COOKIE_SIZE
+3, &hvr
[hvr_size
]);
806 hvr
[hvr_size
++] = prestate
->hsk_write_seq
;
808 _gnutls_write_uint24(0, &hvr
[hvr_size
]);
811 _gnutls_write_uint24(COOKIE_SIZE
+3, &hvr
[hvr_size
]);
815 hvr
[hvr_size
++] = 254;
816 hvr
[hvr_size
++] = 255;
817 hvr
[hvr_size
++] = COOKIE_SIZE
;
819 ret
= _gnutls_hmac_fast(C_HASH
, key
->data
, key
->size
, client_data
, client_data_size
, digest
);
821 return gnutls_assert_val(ret
);
823 memcpy(&hvr
[hvr_size
], digest
, COOKIE_MAC_SIZE
);
824 hvr_size
+= COOKIE_MAC_SIZE
;
826 ret
= push_func(ptr
, hvr
, hvr_size
);
828 ret
= GNUTLS_E_PUSH_ERROR
;
834 * gnutls_dtls_cookie_verify:
835 * @key: is a random key to be used at cookie generation
836 * @client_data: contains data identifying the client (i.e. address)
837 * @client_data_size: The size of client's data
838 * @_msg: An incoming message that initiates a connection.
839 * @msg_size: The size of the message.
840 * @prestate: The cookie of this client.
842 * This function will verify an incoming message for
843 * a valid cookie. If a valid cookie is returned then
844 * it should be associated with the session using
845 * gnutls_dtls_prestate_set();
847 * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code.
851 int gnutls_dtls_cookie_verify(gnutls_datum_t
* key
,
852 void* client_data
, size_t client_data_size
,
853 void* _msg
, size_t msg_size
, gnutls_dtls_prestate_st
* prestate
)
855 gnutls_datum_t cookie
;
857 unsigned int pos
, sid_size
;
858 uint8_t * msg
= _msg
;
859 uint8_t digest
[C_HASH_SIZE
];
861 if (key
== NULL
|| key
->data
== NULL
|| key
->size
== 0)
862 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
867 * session_id - 1 byte length + content
868 * cookie - 1 byte length + content
871 pos
= 34+DTLS_RECORD_HEADER_SIZE
+DTLS_HANDSHAKE_HEADER_SIZE
;
873 if (msg_size
< pos
+1)
874 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
876 sid_size
= msg
[pos
++];
878 if (sid_size
> 32 || msg_size
< pos
+sid_size
+1)
879 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
882 cookie
.size
= msg
[pos
++];
884 if (msg_size
< pos
+cookie
.size
+1)
885 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
887 cookie
.data
= &msg
[pos
];
888 if (cookie
.size
!= COOKIE_SIZE
)
890 if (cookie
.size
> 0) _gnutls_audit_log(NULL
, "Received cookie with illegal size %d. Expected %d\n", (int)cookie
.size
, COOKIE_SIZE
);
891 return gnutls_assert_val(GNUTLS_E_BAD_COOKIE
);
894 ret
= _gnutls_hmac_fast(C_HASH
, key
->data
, key
->size
, client_data
, client_data_size
, digest
);
896 return gnutls_assert_val(ret
);
898 if (memcmp(digest
, cookie
.data
, COOKIE_MAC_SIZE
) != 0)
899 return gnutls_assert_val(GNUTLS_E_BAD_COOKIE
);
901 prestate
->record_seq
= msg
[10]; /* client's record seq */
902 prestate
->hsk_read_seq
= msg
[DTLS_RECORD_HEADER_SIZE
+5]; /* client's hsk seq */
903 prestate
->hsk_write_seq
= 0;/* we always send zero for this msg */
909 * gnutls_dtls_prestate_set:
910 * @session: a new session
911 * @prestate: contains the client's prestate
913 * This function will associate the prestate acquired by
914 * the cookie authentication with the client, with the newly
915 * established session.
919 void gnutls_dtls_prestate_set(gnutls_session_t session
, gnutls_dtls_prestate_st
* prestate
)
921 record_parameters_st
*params
;
924 if (prestate
== NULL
)
927 /* we do not care about read_params, since we accept anything
930 ret
= _gnutls_epoch_get (session
, EPOCH_WRITE_CURRENT
, ¶ms
);
934 params
->write
.sequence_number
.i
[7] = prestate
->record_seq
;
936 session
->internals
.dtls
.hsk_read_seq
= prestate
->hsk_read_seq
;
937 session
->internals
.dtls
.hsk_write_seq
= prestate
->hsk_write_seq
+ 1;
941 * gnutls_record_get_discarded:
942 * @session: is a #gnutls_session_t structure.
944 * Returns the number of discarded packets in a
947 * Returns: The number of discarded packets.
951 unsigned int gnutls_record_get_discarded (gnutls_session_t session
)
953 return session
->internals
.dtls
.packets_dropped
;