fb9c71f3965c193e096c42cd735966d5882555d0
[platform/upstream/iotivity.git] / extlibs / tinydtls / 0001-Added-support-in-tinyDTLS-to-support-rehandshake.patch
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
5
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.
11
12
13 Change-Id: I6e256921215c1a22e9e5013499c4dfd98659f8cc
14 Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
15 ---
16  extlibs/tinydtls/dtls.c |   74 +++++++++++++++++++++++++++++++++++++++++++----
17  1 file changed, 68 insertions(+), 6 deletions(-)
18
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));
25  }
26  
27 +/**
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.
32 + *
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
37 + * client
38 + */
39 +static int
40 +hs_attempt_with_existing_peer(uint8_t *msg, size_t msglen,
41 +    dtls_peer_t *peer)
42 +{
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) {
50 +            return 1;
51 +          }
52 +        }
53 +      }
54 +    }
55 +    return 0;
56 +}
57 +
58  /** Dump out the cipher keys and IVs used for the symetric cipher. */
59  static void dtls_debug_keyblock(dtls_security_parameters_t *config)
60  {
61 @@ -1540,6 +1571,7 @@ static int
62  dtls_verify_peer(dtls_context_t *ctx, 
63                  dtls_peer_t *peer, 
64                  session_t *session,
65 +                const dtls_state_t state,
66                  uint8 *data, size_t data_length)
67  {
68    uint8 buf[DTLS_HV_LENGTH + DTLS_COOKIE_LENGTH];
69 @@ -1595,9 +1627,11 @@ dtls_verify_peer(dtls_context_t *ctx,
70  
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,
75 -                                    buf, p - buf, 0);
76 +  err = dtls_send_handshake_msg_hash(ctx,
77 +                    state == DTLS_STATE_CONNECTED ? peer : NULL,
78 +                    session,
79 +                    DTLS_HT_HELLO_VERIFY_REQUEST,
80 +                    buf, p - buf, 0);
81    if (err < 0) {
82      dtls_warn("cannot send HelloVerify request\n");
83    }
84 @@ -3209,7 +3243,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
85  
86    case DTLS_HT_CLIENT_HELLO:
87  
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);
92      }
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.
96      */
97 -    err = dtls_verify_peer(ctx, peer, session, data, data_length);
98 +    err = dtls_verify_peer(ctx, peer, session, state, data, data_length);
99      if (err < 0) {
100        dtls_warn("error in dtls_verify_peer err: %i\n", err);
101        return err;
102 @@ -3236,7 +3270,23 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session,
103  
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 */
117 +
118 +       dtls_free_peer(peer);
119 +       peer = NULL;
120 +    }
121      if (!peer) {
122 +      dtls_debug("creating new peer\n");
123        dtls_security_parameters_t *security;
124  
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) */
129    int err;
130 +  int bypass_epoch_check = 0;
131  
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,
135      if (peer) {
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;
146 +        } else {
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,
151         }
152          return err;
153        }
154 +    } else {
155        role = peer->role;
156        state = peer->state;
157 +      }
158      } else {
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. */
164  
165 -      if (peer) {
166 +      if (peer && !bypass_epoch_check) {
167         uint16_t expected_epoch = dtls_security_params(peer)->epoch;
168         uint16_t msg_epoch = 
169           dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->epoch);
170 -- 
171 1.7.9.5
172