1 From c78aa91005b7b9542d595dc32d8c8fe020d2257d Mon Sep 17 00:00:00 2001
2 From: Sachin Agrawal <sachin.agrawal@intel.com>
3 Date: Wed, 21 Jan 2015 08:55:00 -0800
4 Subject: [PATCH 1/1] Added support in tinyDTLS to support rehandshake
6 As per RFC 6347 section 4.2.8, DTLS Server should support requests
7 from clients who have silently abandoned the existing association
8 and initiated a new handshake request by sending a ClientHello.
9 Code is updated to detect this scenario and delete the old
10 association when client successfully responds to HelloVerifyRequest.
13 Change-Id: I6e256921215c1a22e9e5013499c4dfd98659f8cc
14 Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
16 extlibs/tinydtls/dtls.c | 74 +++++++++++++++++++++++++++++++++++++++++++----
17 1 file changed, 68 insertions(+), 6 deletions(-)
19 diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c
20 index 779e701..111a65d 100644
21 --- a/extlibs/tinydtls/dtls.c
22 +++ b/extlibs/tinydtls/dtls.c
23 @@ -529,6 +529,37 @@ known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) {
24 (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code));
28 + * This method detects if we already have a established DTLS session with
29 + * peer and the peer is attempting to perform a fresh handshake by sending
30 + * messages with epoch = 0. This is to handle situations mentioned in
31 + * RFC 6347 - section 4.2.8.
33 + * @param msg The packet received from Client
34 + * @param msglen Packet length
35 + * @param peer peer who is the sender for this packet
36 + * @return @c 1 if this is a rehandshake attempt by
40 +hs_attempt_with_existing_peer(uint8_t *msg, size_t msglen,
43 + if ((peer) && (peer->state == DTLS_STATE_CONNECTED)) {
44 + if (msg[0] == DTLS_CT_HANDSHAKE) {
45 + uint16_t msg_epoch = dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->epoch);
46 + if (msg_epoch == 0) {
47 + dtls_handshake_header_t * hs_header = DTLS_HANDSHAKE_HEADER(msg + DTLS_RH_LENGTH);
48 + if (hs_header->msg_type == DTLS_HT_CLIENT_HELLO ||
49 + hs_header->msg_type == DTLS_HT_HELLO_REQUEST) {
58 /** Dump out the cipher keys and IVs used for the symetric cipher. */
59 static void dtls_debug_keyblock(dtls_security_parameters_t *config)
61 @@ -1540,6 +1571,7 @@ static int
62 dtls_verify_peer(dtls_context_t *ctx,
65 + const dtls_state_t state,
66 uint8 *data, size_t data_length)
68 uint8 buf[DTLS_HV_LENGTH + DTLS_COOKIE_LENGTH];
69 @@ -1595,9 +1627,11 @@ dtls_verify_peer(dtls_context_t *ctx,
71 /* TODO use the same record sequence number as in the ClientHello,
72 see 4.2.1. Denial-of-Service Countermeasures */
73 - err = dtls_send_handshake_msg_hash(ctx, peer, session,
74 - DTLS_HT_HELLO_VERIFY_REQUEST,
76 + err = dtls_send_handshake_msg_hash(ctx,
77 + state == DTLS_STATE_CONNECTED ? peer : NULL,
79 + DTLS_HT_HELLO_VERIFY_REQUEST,
82 dtls_warn("cannot send HelloVerify request\n");
84 @@ -3209,7 +3243,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
86 case DTLS_HT_CLIENT_HELLO:
88 - if ((peer && state != DTLS_STATE_CONNECTED) ||
89 + if ((peer && state != DTLS_STATE_CONNECTED && state != DTLS_STATE_WAIT_CLIENTHELLO) ||
90 (!peer && state != DTLS_STATE_WAIT_CLIENTHELLO)) {
91 return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE);
93 @@ -3223,7 +3257,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
94 Anything else will be rejected. Fragementation is not allowed
95 here as it would require peer state as well.
97 - err = dtls_verify_peer(ctx, peer, session, data, data_length);
98 + err = dtls_verify_peer(ctx, peer, session, state, data, data_length);
100 dtls_warn("error in dtls_verify_peer err: %i\n", err);
102 @@ -3236,7 +3270,23 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
104 /* At this point, we have a good relationship with this peer. This
105 * state is left for re-negotiation of key material. */
106 + /* As per RFC 6347 - section 4.2.8 if this is an attempt to
107 + * rehandshake, we can delete the existing key material
108 + * as the client has demonstrated reachibility by completing
109 + * the cookie exchange */
110 + if (peer && state == DTLS_STATE_WAIT_CLIENTHELLO) {
111 + dtls_debug("removing the peer\n");
112 +#ifndef WITH_CONTIKI
113 + HASH_DEL_PEER(ctx->peers, peer);
114 +#else /* WITH_CONTIKI */
115 + list_remove(ctx->peers, peer);
116 +#endif /* WITH_CONTIKI */
118 + dtls_free_peer(peer);
122 + dtls_debug("creating new peer\n");
123 dtls_security_parameters_t *security;
125 /* msg contains a Client Hello with a valid cookie, so we can
126 @@ -3594,6 +3644,7 @@ dtls_handle_message(dtls_context_t *ctx,
127 int data_length; /* length of decrypted payload
128 (without MAC and padding) */
130 + int bypass_epoch_check = 0;
132 /* check if we have DTLS state for addr/port/ifindex */
133 peer = dtls_get_peer(ctx, session);
134 @@ -3613,6 +3664,15 @@ dtls_handle_message(dtls_context_t *ctx,
136 data_length = decrypt_verify(peer, msg, rlen, &data);
137 if (data_length < 0) {
138 + if (hs_attempt_with_existing_peer(msg, rlen, peer)) {
139 + data = msg + DTLS_RH_LENGTH;
140 + data_length = rlen - DTLS_RH_LENGTH;
141 + state = DTLS_STATE_WAIT_CLIENTHELLO;
142 + role = DTLS_SERVER;
143 + /* Bypass epoch check as the epoch for incoming msg is 0
144 + and expected epoch MAY be different */
145 + bypass_epoch_check = 1;
147 int err = dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
148 dtls_info("decrypt_verify() failed\n");
149 if (peer->state < DTLS_STATE_CONNECTED) {
150 @@ -3623,8 +3683,10 @@ dtls_handle_message(dtls_context_t *ctx,
159 /* is_record() ensures that msg contains at least a record header */
160 data = msg + DTLS_RH_LENGTH;
161 @@ -3677,7 +3739,7 @@ dtls_handle_message(dtls_context_t *ctx,
162 /* Handshake messages other than Finish must use the current
163 * epoch, Finish has epoch + 1. */
166 + if (peer && !bypass_epoch_check) {
167 uint16_t expected_epoch = dtls_security_params(peer)->epoch;
169 dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->epoch);