1 From e25d93dec6d2907430f3680ad5fbdfedc1ee94d8 Mon Sep 17 00:00:00 2001
2 From: Sachin Agrawal <sachin.agrawal@intel.com>
3 Date: Sun, 15 Feb 2015 22:16:43 -0800
4 Subject: [PATCH 1/1] Bug Fix in earlier rehandhsake implementation
6 Identified a corner case in earlier rehandshake implementation where if
7 no data transfer takes place between client and Server before re-handshake
8 is issued, re-handshake process was failing. DTLS state machine does not
9 update it's state at Server until the first data packet was received from
10 client. Updated logic to detect for 're-handshake' situation when epoch
11 mis-match happens. Also updated dtls-client test app to conveniently test
12 the feature. Use 'client:rehandshake' command for testing.
14 Change-Id: Idfaad7d477508603c35ad7948ca7c8f05e3228d0
15 Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
17 extlibs/tinydtls/dtls.c | 44 ++++++++++++++++++----------------
18 extlibs/tinydtls/tests/dtls-client.c | 27 +++++++++++++++++++++
19 2 files changed, 50 insertions(+), 21 deletions(-)
21 diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c
22 index a87d7f1..a923386 100644
23 --- a/extlibs/tinydtls/dtls.c
24 +++ b/extlibs/tinydtls/dtls.c
25 @@ -1562,6 +1562,7 @@ static void dtls_destroy_peer(dtls_context_t *ctx, dtls_peer_t *peer, int unlink
26 * \param ctx The DTLS context.
27 * \param peer The remote party we are talking to, if any.
28 * \param session Transport address of the remote peer.
29 + * \param state Current state of the connection.
30 * \param msg The received datagram.
31 * \param msglen Length of \p msg.
32 * \return \c 1 if msg is a Client Hello with a valid cookie, \c 0 or
33 @@ -3644,7 +3645,6 @@ dtls_handle_message(dtls_context_t *ctx,
34 int data_length; /* length of decrypted payload
35 (without MAC and padding) */
37 - int bypass_epoch_check = 0;
39 /* check if we have DTLS state for addr/port/ifindex */
40 peer = dtls_get_peer(ctx, session);
41 @@ -3668,24 +3668,21 @@ dtls_handle_message(dtls_context_t *ctx,
42 data = msg + DTLS_RH_LENGTH;
43 data_length = rlen - DTLS_RH_LENGTH;
44 state = DTLS_STATE_WAIT_CLIENTHELLO;
46 - /* Bypass epoch check as the epoch for incoming msg is 0
47 - and expected epoch MAY be different */
48 - bypass_epoch_check = 1;
51 - int err = dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
52 - dtls_info("decrypt_verify() failed\n");
53 - if (peer->state < DTLS_STATE_CONNECTED) {
54 - dtls_alert_send_from_err(ctx, peer, &peer->session, err);
55 - peer->state = DTLS_STATE_CLOSED;
56 - /* dtls_stop_retransmission(ctx, peer); */
57 - dtls_destroy_peer(ctx, peer, 1);
63 - state = peer->state;
64 + int err = dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
65 + dtls_info("decrypt_verify() failed\n");
66 + if (peer->state < DTLS_STATE_CONNECTED) {
67 + dtls_alert_send_from_err(ctx, peer, &peer->session, err);
68 + peer->state = DTLS_STATE_CLOSED;
69 + /* dtls_stop_retransmission(ctx, peer); */
70 + dtls_destroy_peer(ctx, peer, 1);
76 + state = peer->state;
79 /* is_record() ensures that msg contains at least a record header */
80 @@ -3739,7 +3736,7 @@ dtls_handle_message(dtls_context_t *ctx,
81 /* Handshake messages other than Finish must use the current
82 * epoch, Finish has epoch + 1. */
84 - if (peer && !bypass_epoch_check) {
86 uint16_t expected_epoch = dtls_security_params(peer)->epoch;
88 dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->epoch);
89 @@ -3754,9 +3751,14 @@ dtls_handle_message(dtls_context_t *ctx,
92 if (expected_epoch != msg_epoch) {
93 - dtls_warn("Wrong epoch, expected %i, got: %i\n",
94 + if (hs_attempt_with_existing_peer(msg, rlen, peer)) {
95 + state = DTLS_STATE_WAIT_CLIENTHELLO;
98 + dtls_warn("Wrong epoch, expected %i, got: %i\n",
99 expected_epoch, msg_epoch);
106 diff --git a/extlibs/tinydtls/tests/dtls-client.c b/extlibs/tinydtls/tests/dtls-client.c
107 index 306a380..05cb98f 100644
108 --- a/extlibs/tinydtls/tests/dtls-client.c
109 +++ b/extlibs/tinydtls/tests/dtls-client.c
110 @@ -44,6 +44,7 @@ typedef struct {
111 static dtls_str output_file = { 0, NULL }; /* output file name */
113 static dtls_context_t *dtls_context = NULL;
114 +static dtls_context_t *orig_dtls_context = NULL;
117 static const unsigned char ecdsa_priv_key[] = {
118 @@ -235,6 +236,7 @@ dtls_handle_read(struct dtls_context_t *ctx) {
119 static void dtls_handle_signal(int sig)
121 dtls_free_context(dtls_context);
122 + dtls_free_context(orig_dtls_context);
123 signal(sig, SIG_DFL);
126 @@ -324,6 +326,12 @@ static dtls_handler_t cb = {
127 #define DTLS_CLIENT_CMD_CLOSE "client:close"
128 #define DTLS_CLIENT_CMD_RENEGOTIATE "client:renegotiate"
130 +/* As per RFC 6347 section 4.2.8, DTLS Server should support requests
131 + * from clients who have silently abandoned the existing association
132 + * and initiated a new handshake request by sending a ClientHello.
133 + * Below command tests this feature.
135 +#define DTLS_CLIENT_CMD_REHANDSHAKE "client:rehandshake"
137 main(int argc, char **argv) {
139 @@ -504,6 +512,24 @@ main(int argc, char **argv) {
140 printf("client: renegotiate connection\n");
141 dtls_renegotiate(dtls_context, &dst);
143 + } else if (len >= strlen(DTLS_CLIENT_CMD_REHANDSHAKE) &&
144 + !memcmp(buf, DTLS_CLIENT_CMD_REHANDSHAKE, strlen(DTLS_CLIENT_CMD_REHANDSHAKE))) {
145 + printf("client: rehandshake connection\n");
146 + if (orig_dtls_context == NULL) {
147 + /* Cache the current context. We cannot free the current context as it will notify
148 + * the Server to close the connection (which we do not want).
150 + orig_dtls_context = dtls_context;
151 + /* Now, Create a new context and attempt to initiate a handshake. */
152 + dtls_context = dtls_new_context(&fd);
153 + if (!dtls_context) {
154 + dtls_emerg("cannot create context\n");
157 + dtls_set_handler(dtls_context, &cb);
158 + dtls_connect(dtls_context, &dst);
162 try_send(dtls_context, &dst);
164 @@ -511,6 +537,7 @@ main(int argc, char **argv) {
167 dtls_free_context(dtls_context);
168 + dtls_free_context(orig_dtls_context);