mbed port of tinydtls

Committer:
ashleymills
Date:
Fri Oct 11 08:46:21 2013 +0000
Revision:
1:bc8a649bad13
Parent:
0:04990d454f45
Cleaned up all the debug stuff I added finding the hash table bug.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ashleymills 0:04990d454f45 1 /* dtls -- a very basic DTLS implementation
ashleymills 0:04990d454f45 2 *
ashleymills 0:04990d454f45 3 * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org>
ashleymills 0:04990d454f45 4 *
ashleymills 0:04990d454f45 5 * Permission is hereby granted, free of charge, to any person
ashleymills 0:04990d454f45 6 * obtaining a copy of this software and associated documentation
ashleymills 0:04990d454f45 7 * files (the "Software"), to deal in the Software without
ashleymills 0:04990d454f45 8 * restriction, including without limitation the rights to use, copy,
ashleymills 0:04990d454f45 9 * modify, merge, publish, distribute, sublicense, and/or sell copies
ashleymills 0:04990d454f45 10 * of the Software, and to permit persons to whom the Software is
ashleymills 0:04990d454f45 11 * furnished to do so, subject to the following conditions:
ashleymills 0:04990d454f45 12 *
ashleymills 0:04990d454f45 13 * The above copyright notice and this permission notice shall be
ashleymills 0:04990d454f45 14 * included in all copies or substantial portions of the Software.
ashleymills 0:04990d454f45 15 *
ashleymills 0:04990d454f45 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
ashleymills 0:04990d454f45 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
ashleymills 0:04990d454f45 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ashleymills 0:04990d454f45 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
ashleymills 0:04990d454f45 20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ashleymills 0:04990d454f45 21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
ashleymills 0:04990d454f45 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
ashleymills 0:04990d454f45 23 * SOFTWARE.
ashleymills 0:04990d454f45 24 */
ashleymills 0:04990d454f45 25
ashleymills 1:bc8a649bad13 26 #define __DEBUG__ 0
ashleymills 0:04990d454f45 27
ashleymills 0:04990d454f45 28 #ifndef __MODULE__
ashleymills 0:04990d454f45 29 #define __MODULE__ "dtls.c"
ashleymills 0:04990d454f45 30 #endif
ashleymills 0:04990d454f45 31 #include "dbg.h"
ashleymills 0:04990d454f45 32
ashleymills 0:04990d454f45 33 #include "config.h"
ashleymills 0:04990d454f45 34
ashleymills 0:04990d454f45 35 #include "dtls_time.h"
ashleymills 0:04990d454f45 36
ashleymills 0:04990d454f45 37 #include <stdio.h>
ashleymills 0:04990d454f45 38 #include <stdlib.h>
ashleymills 0:04990d454f45 39 #ifdef HAVE_ASSERT_H
ashleymills 0:04990d454f45 40 #include <assert.h>
ashleymills 0:04990d454f45 41 #endif
ashleymills 0:04990d454f45 42 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 43 #include <stdlib.h>
ashleymills 0:04990d454f45 44 #include "uthash.h"
ashleymills 0:04990d454f45 45 #else /* WITH_CONTIKI */
ashleymills 0:04990d454f45 46 # ifndef NDEBUG
ashleymills 0:04990d454f45 47 # define DEBUG DEBUG_PRINT
ashleymills 0:04990d454f45 48 # include "net/uip-debug.h"
ashleymills 0:04990d454f45 49 # endif /* NDEBUG */
ashleymills 0:04990d454f45 50 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 51
ashleymills 0:04990d454f45 52 #include "debug.h"
ashleymills 0:04990d454f45 53 #include "numeric.h"
ashleymills 0:04990d454f45 54 #include "netq.h"
ashleymills 0:04990d454f45 55 #include "dtls.h"
ashleymills 0:04990d454f45 56
ashleymills 0:04990d454f45 57 #ifdef WITH_SHA256
ashleymills 0:04990d454f45 58 # include "sha2/sha2.h"
ashleymills 0:04990d454f45 59 #endif
ashleymills 0:04990d454f45 60
ashleymills 0:04990d454f45 61 //#include "bsd_socket.h"
ashleymills 0:04990d454f45 62
ashleymills 0:04990d454f45 63 #define dtls_set_version(H,V) dtls_int_to_uint16(&(H)->version, (V))
ashleymills 0:04990d454f45 64 #define dtls_set_content_type(H,V) ((H)->content_type = (V) & 0xff)
ashleymills 0:04990d454f45 65 #define dtls_set_length(H,V) ((H)->length = (V))
ashleymills 0:04990d454f45 66
ashleymills 0:04990d454f45 67 #define dtls_get_content_type(H) ((H)->content_type & 0xff)
ashleymills 0:04990d454f45 68 #define dtls_get_version(H) dtls_uint16_to_int(&(H)->version)
ashleymills 0:04990d454f45 69 #define dtls_get_epoch(H) dtls_uint16_to_int(&(H)->epoch)
ashleymills 0:04990d454f45 70 #define dtls_get_sequence_number(H) dtls_uint48_to_ulong(&(H)->sequence_number)
ashleymills 0:04990d454f45 71 #define dtls_get_fragment_length(H) dtls_uint24_to_int(&(H)->fragment_length)
ashleymills 0:04990d454f45 72
ashleymills 0:04990d454f45 73 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 74 #define HASH_FIND_PEER(head,sess,out) \
ashleymills 0:04990d454f45 75 HASH_FIND(hh,head,sess,sizeof(session_t),out)
ashleymills 0:04990d454f45 76 #define HASH_ADD_PEER(head,sess,add) \
ashleymills 0:04990d454f45 77 HASH_ADD(hh,head,sess,sizeof(session_t),add)
ashleymills 0:04990d454f45 78 #define HASH_DEL_PEER(head,delptr) \
ashleymills 0:04990d454f45 79 HASH_DELETE(hh,head,delptr)
ashleymills 0:04990d454f45 80 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 81
ashleymills 0:04990d454f45 82 #define DTLS_RH_LENGTH sizeof(dtls_record_header_t)
ashleymills 0:04990d454f45 83 #define DTLS_HS_LENGTH sizeof(dtls_handshake_header_t)
ashleymills 0:04990d454f45 84 #define DTLS_CH_LENGTH sizeof(dtls_client_hello_t) /* no variable length fields! */
ashleymills 0:04990d454f45 85 #define DTLS_HV_LENGTH sizeof(dtls_hello_verify_t)
ashleymills 0:04990d454f45 86 #define DTLS_SH_LENGTH (2 + 32 + 1 + 2 + 1)
ashleymills 0:04990d454f45 87 #define DTLS_CKX_LENGTH 1
ashleymills 0:04990d454f45 88 #define DTLS_FIN_LENGTH 12
ashleymills 0:04990d454f45 89
ashleymills 0:04990d454f45 90 #define HS_HDR_LENGTH DTLS_RH_LENGTH + DTLS_HS_LENGTH
ashleymills 0:04990d454f45 91 #define HV_HDR_LENGTH HS_HDR_LENGTH + DTLS_HV_LENGTH
ashleymills 0:04990d454f45 92
ashleymills 0:04990d454f45 93 #define HIGH(V) (((V) >> 8) & 0xff)
ashleymills 0:04990d454f45 94 #define LOW(V) ((V) & 0xff)
ashleymills 0:04990d454f45 95
ashleymills 0:04990d454f45 96 #define DTLS_RECORD_HEADER(M) ((dtls_record_header_t *)(M))
ashleymills 0:04990d454f45 97 #define DTLS_HANDSHAKE_HEADER(M) ((dtls_handshake_header_t *)(M))
ashleymills 0:04990d454f45 98
ashleymills 0:04990d454f45 99 #define HANDSHAKE(M) ((dtls_handshake_header_t *)((M) + DTLS_RH_LENGTH))
ashleymills 0:04990d454f45 100 #define CLIENTHELLO(M) ((dtls_client_hello_t *)((M) + HS_HDR_LENGTH))
ashleymills 0:04990d454f45 101
ashleymills 0:04990d454f45 102 #define IS_HELLOVERIFY(M,L) \
ashleymills 0:04990d454f45 103 ((L) >= DTLS_HS_LENGTH + DTLS_HV_LENGTH && (M)[0] == DTLS_HT_HELLO_VERIFY_REQUEST)
ashleymills 0:04990d454f45 104 #define IS_SERVERHELLO(M,L) \
ashleymills 0:04990d454f45 105 ((L) >= DTLS_HS_LENGTH + 6 && (M)[0] == DTLS_HT_SERVER_HELLO)
ashleymills 0:04990d454f45 106 #define IS_SERVERHELLODONE(M,L) \
ashleymills 0:04990d454f45 107 ((L) >= DTLS_HS_LENGTH && (M)[0] == DTLS_HT_SERVER_HELLO_DONE)
ashleymills 0:04990d454f45 108 #define IS_FINISHED(M,L) \
ashleymills 0:04990d454f45 109 ((L) >= DTLS_HS_LENGTH + DTLS_FIN_LENGTH && (M)[0] == DTLS_HT_FINISHED)
ashleymills 0:04990d454f45 110
ashleymills 0:04990d454f45 111 /* The length check here should work because dtls_*_to_int() works on
ashleymills 0:04990d454f45 112 * unsigned char. Otherwise, broken messages could cause severe
ashleymills 0:04990d454f45 113 * trouble. Note that this macro jumps out of the current program flow
ashleymills 0:04990d454f45 114 * when the message is too short. Beware!
ashleymills 0:04990d454f45 115 */
ashleymills 0:04990d454f45 116 #define SKIP_VAR_FIELD(P,L,T) { \
ashleymills 0:04990d454f45 117 if (L < dtls_ ## T ## _to_int(P) + sizeof(T)) \
ashleymills 0:04990d454f45 118 goto error; \
ashleymills 0:04990d454f45 119 L -= dtls_ ## T ## _to_int(P) + sizeof(T); \
ashleymills 0:04990d454f45 120 P += dtls_ ## T ## _to_int(P) + sizeof(T); \
ashleymills 0:04990d454f45 121 }
ashleymills 0:04990d454f45 122
ashleymills 0:04990d454f45 123 uint8 _clear[DTLS_MAX_BUF]; /* target buffer message decryption */
ashleymills 0:04990d454f45 124 uint8 _buf[DTLS_MAX_BUF]; /* target buffer for several crypto operations */
ashleymills 0:04990d454f45 125
ashleymills 0:04990d454f45 126 #ifndef NDEBUG
ashleymills 0:04990d454f45 127 void hexdump(const unsigned char *packet, int length);
ashleymills 0:04990d454f45 128 void dump(unsigned char *buf, size_t len);
ashleymills 0:04990d454f45 129 #endif
ashleymills 0:04990d454f45 130
ashleymills 0:04990d454f45 131 /* some constants for the PRF */
ashleymills 0:04990d454f45 132 #define PRF_LABEL(Label) prf_label_##Label
ashleymills 0:04990d454f45 133 #define PRF_LABEL_SIZE(Label) (sizeof(PRF_LABEL(Label)) - 1)
ashleymills 0:04990d454f45 134
ashleymills 0:04990d454f45 135 static const unsigned char prf_label_master[] = "master secret";
ashleymills 0:04990d454f45 136 static const unsigned char prf_label_key[] = "key expansion";
ashleymills 0:04990d454f45 137 static const unsigned char prf_label_client[] = "client";
ashleymills 0:04990d454f45 138 static const unsigned char prf_label_server[] = "server";
ashleymills 0:04990d454f45 139 static const unsigned char prf_label_finished[] = " finished";
ashleymills 0:04990d454f45 140
ashleymills 0:04990d454f45 141 extern void netq_init();
ashleymills 0:04990d454f45 142 extern void crypto_init();
ashleymills 0:04990d454f45 143 extern void peer_init();
ashleymills 0:04990d454f45 144
ashleymills 0:04990d454f45 145 dtls_context_t the_dtls_context;
ashleymills 0:04990d454f45 146
ashleymills 0:04990d454f45 147 void
ashleymills 0:04990d454f45 148 dtls_init() {
ashleymills 0:04990d454f45 149 dtls_clock_init();
ashleymills 0:04990d454f45 150 netq_init();
ashleymills 0:04990d454f45 151 crypto_init();
ashleymills 0:04990d454f45 152 peer_init();
ashleymills 0:04990d454f45 153 }
ashleymills 0:04990d454f45 154
ashleymills 0:04990d454f45 155 /* Calls cb_alert() with given arguments if defined, otherwise an
ashleymills 0:04990d454f45 156 * error message is logged and the result is -1. This is just an
ashleymills 0:04990d454f45 157 * internal helper.
ashleymills 0:04990d454f45 158 */
ashleymills 0:04990d454f45 159 #define CALL(Context, which, ...) \
ashleymills 0:04990d454f45 160 ((Context)->h && (Context)->h->which \
ashleymills 0:04990d454f45 161 ? (Context)->h->which((Context), ##__VA_ARGS__) \
ashleymills 0:04990d454f45 162 : -1)
ashleymills 0:04990d454f45 163
ashleymills 0:04990d454f45 164 /**
ashleymills 0:04990d454f45 165 * Sends the fragment of length \p buflen given in \p buf to the
ashleymills 0:04990d454f45 166 * specified \p peer. The data will be MAC-protected and encrypted
ashleymills 0:04990d454f45 167 * according to the selected cipher and split into one or more DTLS
ashleymills 0:04990d454f45 168 * records of the specified \p type. This function returns the number
ashleymills 0:04990d454f45 169 * of bytes that were sent, or \c -1 if an error occurred.
ashleymills 0:04990d454f45 170 *
ashleymills 0:04990d454f45 171 * \param ctx The DTLS context to use.
ashleymills 0:04990d454f45 172 * \param peer The remote peer.
ashleymills 0:04990d454f45 173 * \param type The content type of the record.
ashleymills 0:04990d454f45 174 * \param buf The data to send.
ashleymills 0:04990d454f45 175 * \param buflen The actual length of \p buf.
ashleymills 0:04990d454f45 176 * \return Less than zero on error, the number of bytes written otherwise.
ashleymills 0:04990d454f45 177 */
ashleymills 0:04990d454f45 178 int dtls_send(dtls_context_t *ctx, dtls_peer_t *peer, unsigned char type,
ashleymills 0:04990d454f45 179 uint8 *buf, size_t buflen);
ashleymills 0:04990d454f45 180
ashleymills 0:04990d454f45 181 /**
ashleymills 0:04990d454f45 182 * Stops ongoing retransmissions of handshake messages for @p peer.
ashleymills 0:04990d454f45 183 */
ashleymills 0:04990d454f45 184 void dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer);
ashleymills 0:04990d454f45 185
ashleymills 0:04990d454f45 186 dtls_peer_t *
ashleymills 0:04990d454f45 187 dtls_get_peer(const dtls_context_t *ctx, const session_t *session) {
ashleymills 0:04990d454f45 188 DBG("dtls_get_peer");
ashleymills 0:04990d454f45 189 dtls_peer_t *p = NULL;
ashleymills 0:04990d454f45 190 DBG("trying to get hash for the following byte sequence: ");
ashleymills 1:bc8a649bad13 191 #if __DEBUG__ > 0
ashleymills 0:04990d454f45 192 for(uint8_t i=0; i<sizeof(session_t); i++) {
ashleymills 0:04990d454f45 193 DBGX("%x ",((uint8_t*)session)[i]);
ashleymills 0:04990d454f45 194 }
ashleymills 1:bc8a649bad13 195 #endif
ashleymills 0:04990d454f45 196 DBGX("\r\n");
ashleymills 0:04990d454f45 197 DBG("session size: %u, AF: %u, address: %s:%d, ifnumber: %d",
ashleymills 0:04990d454f45 198 session->size,
ashleymills 0:04990d454f45 199 session->addr.sin.sin_family,
ashleymills 0:04990d454f45 200 inet_ntoa(session->addr.sin.sin_addr),
ashleymills 0:04990d454f45 201 ntohs(session->addr.sin.sin_port),
ashleymills 0:04990d454f45 202 session->ifindex
ashleymills 0:04990d454f45 203 );
ashleymills 0:04990d454f45 204
ashleymills 0:04990d454f45 205 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 206 HASH_FIND_PEER(ctx->peers, session, p);
ashleymills 0:04990d454f45 207 #else /* WITH_CONTIKI */
ashleymills 0:04990d454f45 208 for (p = list_head(ctx->peers); p; p = list_item_next(p))
ashleymills 0:04990d454f45 209 if (dtls_session_equals(&p->session, session))
ashleymills 0:04990d454f45 210 return p;
ashleymills 0:04990d454f45 211 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 212 DBG("hash returned pointer to peer @ %u",p);
ashleymills 0:04990d454f45 213 return p;
ashleymills 0:04990d454f45 214 }
ashleymills 0:04990d454f45 215
ashleymills 0:04990d454f45 216 void
ashleymills 0:04990d454f45 217 dtls_add_peer(dtls_context_t *ctx, dtls_peer_t *peer) {
ashleymills 0:04990d454f45 218 DBG("dtls_add_peer");
ashleymills 0:04990d454f45 219 DBG("Trying to add peer @ %u with session byte sequence:",peer);
ashleymills 1:bc8a649bad13 220 #if __DEBUG__ > 0
ashleymills 0:04990d454f45 221 for(uint8_t i=0; i<sizeof(session_t); i++) {
ashleymills 0:04990d454f45 222 DBGX("%x ",((uint8_t*)(&peer->session))[i]);
ashleymills 0:04990d454f45 223 }
ashleymills 1:bc8a649bad13 224 #endif
ashleymills 0:04990d454f45 225 DBGX("\r\n");
ashleymills 0:04990d454f45 226 DBG("session size: %u, address: %s:%d, ifnumber: %d",
ashleymills 0:04990d454f45 227 peer->session.size,
ashleymills 0:04990d454f45 228 inet_ntoa(peer->session.addr.sin.sin_addr),
ashleymills 0:04990d454f45 229 ntohs(peer->session.addr.sin.sin_port),
ashleymills 0:04990d454f45 230 peer->session.ifindex
ashleymills 0:04990d454f45 231 );
ashleymills 0:04990d454f45 232 //#define HASH_ADD_PEER(head,sess,add) \
ashleymills 0:04990d454f45 233 //HASH_ADD(hh,head,sess,sizeof(session_t),add)
ashleymills 0:04990d454f45 234 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 235 HASH_ADD_PEER(ctx->peers, session, peer);
ashleymills 1:bc8a649bad13 236 #else // WITH_CONTIKI
ashleymills 0:04990d454f45 237 list_add(ctx->peers, peer);
ashleymills 1:bc8a649bad13 238 #endif // WITH_CONTIKI
ashleymills 0:04990d454f45 239 }
ashleymills 0:04990d454f45 240
ashleymills 0:04990d454f45 241 int
ashleymills 0:04990d454f45 242 dtls_write(struct dtls_context_t *ctx,
ashleymills 0:04990d454f45 243 session_t *dst, uint8 *buf, size_t len) {
ashleymills 0:04990d454f45 244
ashleymills 0:04990d454f45 245 dtls_peer_t *peer = dtls_get_peer(ctx, dst);
ashleymills 0:04990d454f45 246
ashleymills 0:04990d454f45 247 /* Check if peer connection already exists */
ashleymills 0:04990d454f45 248 if (!peer) { /* no ==> create one */
ashleymills 0:04990d454f45 249 int res;
ashleymills 0:04990d454f45 250
ashleymills 0:04990d454f45 251 /* dtls_connect() returns a value greater than zero if a new
ashleymills 0:04990d454f45 252 * connection attempt is made, 0 for session reuse. */
ashleymills 0:04990d454f45 253 res = dtls_connect(ctx, dst);
ashleymills 0:04990d454f45 254
ashleymills 0:04990d454f45 255 return (res >= 0) ? 0 : res;
ashleymills 0:04990d454f45 256 } else { /* a session exists, check if it is in state connected */
ashleymills 0:04990d454f45 257
ashleymills 0:04990d454f45 258 if (peer->state != DTLS_STATE_CONNECTED) {
ashleymills 0:04990d454f45 259 return 0;
ashleymills 0:04990d454f45 260 } else {
ashleymills 0:04990d454f45 261 return dtls_send(ctx, peer, DTLS_CT_APPLICATION_DATA, buf, len);
ashleymills 0:04990d454f45 262 }
ashleymills 0:04990d454f45 263 }
ashleymills 0:04990d454f45 264 }
ashleymills 0:04990d454f45 265
ashleymills 0:04990d454f45 266 int
ashleymills 0:04990d454f45 267 dtls_get_cookie(uint8 *msg, int msglen, uint8 **cookie) {
ashleymills 0:04990d454f45 268 /* To access the cookie, we have to determine the session id's
ashleymills 0:04990d454f45 269 * length and skip the whole thing. */
ashleymills 0:04990d454f45 270 if (msglen < DTLS_HS_LENGTH + DTLS_CH_LENGTH + sizeof(uint8)
ashleymills 0:04990d454f45 271 || dtls_uint16_to_int(msg + DTLS_HS_LENGTH) != DTLS_VERSION)
ashleymills 0:04990d454f45 272 return -1;
ashleymills 0:04990d454f45 273 msglen -= DTLS_HS_LENGTH + DTLS_CH_LENGTH;
ashleymills 0:04990d454f45 274 msg += DTLS_HS_LENGTH + DTLS_CH_LENGTH;
ashleymills 0:04990d454f45 275
ashleymills 0:04990d454f45 276 SKIP_VAR_FIELD(msg, msglen, uint8); /* skip session id */
ashleymills 0:04990d454f45 277
ashleymills 0:04990d454f45 278 if (msglen < (*msg & 0xff) + sizeof(uint8))
ashleymills 0:04990d454f45 279 return -1;
ashleymills 0:04990d454f45 280
ashleymills 0:04990d454f45 281 *cookie = msg + sizeof(uint8);
ashleymills 0:04990d454f45 282 return dtls_uint8_to_int(msg);
ashleymills 0:04990d454f45 283
ashleymills 0:04990d454f45 284 error:
ashleymills 0:04990d454f45 285 return -1;
ashleymills 0:04990d454f45 286 }
ashleymills 0:04990d454f45 287
ashleymills 0:04990d454f45 288 int
ashleymills 0:04990d454f45 289 dtls_create_cookie(dtls_context_t *ctx,
ashleymills 0:04990d454f45 290 session_t *session,
ashleymills 0:04990d454f45 291 uint8 *msg, int msglen,
ashleymills 0:04990d454f45 292 uint8 *cookie, int *clen) {
ashleymills 0:04990d454f45 293 unsigned char buf[DTLS_HMAC_MAX];
ashleymills 0:04990d454f45 294 size_t len, e;
ashleymills 0:04990d454f45 295
ashleymills 0:04990d454f45 296 /* create cookie with HMAC-SHA256 over:
ashleymills 0:04990d454f45 297 * - SECRET
ashleymills 0:04990d454f45 298 * - session parameters (only IP address?)
ashleymills 0:04990d454f45 299 * - client version
ashleymills 0:04990d454f45 300 * - random gmt and bytes
ashleymills 0:04990d454f45 301 * - session id
ashleymills 0:04990d454f45 302 * - cipher_suites
ashleymills 0:04990d454f45 303 * - compression method
ashleymills 0:04990d454f45 304 */
ashleymills 0:04990d454f45 305
ashleymills 0:04990d454f45 306 /* We use our own buffer as hmac_context instead of a dynamic buffer
ashleymills 0:04990d454f45 307 * created by dtls_hmac_new() to separate storage space for cookie
ashleymills 0:04990d454f45 308 * creation from storage that is used in real sessions. Note that
ashleymills 0:04990d454f45 309 * the buffer size must fit with the default hash algorithm (see
ashleymills 0:04990d454f45 310 * implementation of dtls_hmac_context_new()). */
ashleymills 0:04990d454f45 311
ashleymills 0:04990d454f45 312 dtls_hmac_context_t hmac_context;
ashleymills 0:04990d454f45 313 dtls_hmac_init(&hmac_context, ctx->cookie_secret, DTLS_COOKIE_SECRET_LENGTH);
ashleymills 0:04990d454f45 314
ashleymills 0:04990d454f45 315 dtls_hmac_update(&hmac_context,
ashleymills 0:04990d454f45 316 (unsigned char *)&session->addr, session->size);
ashleymills 0:04990d454f45 317
ashleymills 0:04990d454f45 318 /* feed in the beginning of the Client Hello up to and including the
ashleymills 0:04990d454f45 319 session id */
ashleymills 0:04990d454f45 320 e = sizeof(dtls_client_hello_t);
ashleymills 0:04990d454f45 321 e += (*(msg + DTLS_HS_LENGTH + e) & 0xff) + sizeof(uint8);
ashleymills 0:04990d454f45 322
ashleymills 0:04990d454f45 323 dtls_hmac_update(&hmac_context, msg + DTLS_HS_LENGTH, e);
ashleymills 0:04990d454f45 324
ashleymills 0:04990d454f45 325 /* skip cookie bytes and length byte */
ashleymills 0:04990d454f45 326 e += *(uint8 *)(msg + DTLS_HS_LENGTH + e) & 0xff;
ashleymills 0:04990d454f45 327 e += sizeof(uint8);
ashleymills 0:04990d454f45 328
ashleymills 0:04990d454f45 329 dtls_hmac_update(&hmac_context,
ashleymills 0:04990d454f45 330 msg + DTLS_HS_LENGTH + e,
ashleymills 0:04990d454f45 331 dtls_get_fragment_length(DTLS_HANDSHAKE_HEADER(msg)) - e);
ashleymills 0:04990d454f45 332
ashleymills 0:04990d454f45 333 len = dtls_hmac_finalize(&hmac_context, buf);
ashleymills 0:04990d454f45 334
ashleymills 0:04990d454f45 335 if (len < *clen) {
ashleymills 0:04990d454f45 336 memset(cookie + len, 0, *clen - len);
ashleymills 0:04990d454f45 337 *clen = len;
ashleymills 0:04990d454f45 338 }
ashleymills 0:04990d454f45 339
ashleymills 0:04990d454f45 340 memcpy(cookie, buf, *clen);
ashleymills 0:04990d454f45 341 return 1;
ashleymills 0:04990d454f45 342 }
ashleymills 0:04990d454f45 343
ashleymills 0:04990d454f45 344 #ifdef DTLS_CHECK_CONTENTTYPE
ashleymills 0:04990d454f45 345 /* used to check if a received datagram contains a DTLS message */
ashleymills 0:04990d454f45 346 static char const content_types[] = {
ashleymills 0:04990d454f45 347 DTLS_CT_CHANGE_CIPHER_SPEC,
ashleymills 0:04990d454f45 348 DTLS_CT_ALERT,
ashleymills 0:04990d454f45 349 DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 350 DTLS_CT_APPLICATION_DATA,
ashleymills 0:04990d454f45 351 0 /* end marker */
ashleymills 0:04990d454f45 352 };
ashleymills 0:04990d454f45 353 #endif
ashleymills 0:04990d454f45 354
ashleymills 0:04990d454f45 355 /**
ashleymills 0:04990d454f45 356 * Checks if \p msg points to a valid DTLS record. If
ashleymills 0:04990d454f45 357 *
ashleymills 0:04990d454f45 358 */
ashleymills 0:04990d454f45 359 static unsigned int
ashleymills 0:04990d454f45 360 is_record(uint8 *msg, int msglen) {
ashleymills 0:04990d454f45 361 unsigned int rlen = 0;
ashleymills 0:04990d454f45 362
ashleymills 0:04990d454f45 363 if (msglen >= DTLS_RH_LENGTH /* FIXME allow empty records? */
ashleymills 0:04990d454f45 364 #ifdef DTLS_CHECK_CONTENTTYPE
ashleymills 0:04990d454f45 365 && strchr(content_types, msg[0])
ashleymills 0:04990d454f45 366 #endif
ashleymills 0:04990d454f45 367 && msg[1] == HIGH(DTLS_VERSION)
ashleymills 0:04990d454f45 368 && msg[2] == LOW(DTLS_VERSION))
ashleymills 0:04990d454f45 369 {
ashleymills 0:04990d454f45 370 rlen = DTLS_RH_LENGTH +
ashleymills 0:04990d454f45 371 dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->length);
ashleymills 0:04990d454f45 372
ashleymills 0:04990d454f45 373 /* we do not accept wrong length field in record header */
ashleymills 0:04990d454f45 374 if (rlen > msglen)
ashleymills 0:04990d454f45 375 rlen = 0;
ashleymills 0:04990d454f45 376 }
ashleymills 0:04990d454f45 377
ashleymills 0:04990d454f45 378 return rlen;
ashleymills 0:04990d454f45 379 }
ashleymills 0:04990d454f45 380
ashleymills 0:04990d454f45 381 /**
ashleymills 0:04990d454f45 382 * Initializes \p buf as record header. The caller must ensure that \p
ashleymills 0:04990d454f45 383 * buf is capable of holding at least \c sizeof(dtls_record_header_t)
ashleymills 0:04990d454f45 384 * bytes. Increments sequence number counter of \p peer.
ashleymills 0:04990d454f45 385 * \return pointer to the next byte after the written header
ashleymills 0:04990d454f45 386 */
ashleymills 0:04990d454f45 387 static inline uint8 *
ashleymills 0:04990d454f45 388 dtls_set_record_header(uint8 type, dtls_peer_t *peer, uint8 *buf) {
ashleymills 0:04990d454f45 389
ashleymills 0:04990d454f45 390 dtls_int_to_uint8(buf, type);
ashleymills 0:04990d454f45 391 buf += sizeof(uint8);
ashleymills 0:04990d454f45 392
ashleymills 0:04990d454f45 393 dtls_int_to_uint16(buf, DTLS_VERSION);
ashleymills 0:04990d454f45 394 buf += sizeof(uint16);
ashleymills 0:04990d454f45 395
ashleymills 0:04990d454f45 396 if (peer) {
ashleymills 0:04990d454f45 397 memcpy(buf, &peer->epoch, sizeof(uint16) + sizeof(uint48));
ashleymills 0:04990d454f45 398
ashleymills 0:04990d454f45 399 /* increment record sequence counter by 1 */
ashleymills 0:04990d454f45 400 inc_uint(uint48, peer->rseq);
ashleymills 0:04990d454f45 401 } else {
ashleymills 0:04990d454f45 402 memset(buf, 0, sizeof(uint16) + sizeof(uint48));
ashleymills 0:04990d454f45 403 }
ashleymills 0:04990d454f45 404
ashleymills 0:04990d454f45 405 buf += sizeof(uint16) + sizeof(uint48);
ashleymills 0:04990d454f45 406
ashleymills 0:04990d454f45 407 memset(buf, 0, sizeof(uint16));
ashleymills 0:04990d454f45 408 return buf + sizeof(uint16);
ashleymills 0:04990d454f45 409 }
ashleymills 0:04990d454f45 410
ashleymills 0:04990d454f45 411 /**
ashleymills 0:04990d454f45 412 * Initializes \p buf as handshake header. The caller must ensure that \p
ashleymills 0:04990d454f45 413 * buf is capable of holding at least \c sizeof(dtls_handshake_header_t)
ashleymills 0:04990d454f45 414 * bytes. Increments message sequence number counter of \p peer.
ashleymills 0:04990d454f45 415 * \return pointer to the next byte after \p buf
ashleymills 0:04990d454f45 416 */
ashleymills 0:04990d454f45 417 static inline uint8 *
ashleymills 0:04990d454f45 418 dtls_set_handshake_header(uint8 type, dtls_peer_t *peer,
ashleymills 0:04990d454f45 419 int length,
ashleymills 0:04990d454f45 420 int frag_offset, int frag_length,
ashleymills 0:04990d454f45 421 uint8 *buf) {
ashleymills 0:04990d454f45 422
ashleymills 0:04990d454f45 423 dtls_int_to_uint8(buf, type);
ashleymills 0:04990d454f45 424 buf += sizeof(uint8);
ashleymills 0:04990d454f45 425
ashleymills 0:04990d454f45 426 dtls_int_to_uint24(buf, length);
ashleymills 0:04990d454f45 427 buf += sizeof(uint24);
ashleymills 0:04990d454f45 428
ashleymills 0:04990d454f45 429 if (peer) {
ashleymills 0:04990d454f45 430 /* increment handshake message sequence counter by 1 */
ashleymills 0:04990d454f45 431 inc_uint(uint16, peer->hs_state.mseq);
ashleymills 0:04990d454f45 432
ashleymills 0:04990d454f45 433 /* and copy the result to buf */
ashleymills 0:04990d454f45 434 memcpy(buf, &peer->hs_state.mseq, sizeof(uint16));
ashleymills 0:04990d454f45 435 } else {
ashleymills 0:04990d454f45 436 memset(buf, 0, sizeof(uint16));
ashleymills 0:04990d454f45 437 }
ashleymills 0:04990d454f45 438 buf += sizeof(uint16);
ashleymills 0:04990d454f45 439
ashleymills 0:04990d454f45 440 dtls_int_to_uint24(buf, frag_offset);
ashleymills 0:04990d454f45 441 buf += sizeof(uint24);
ashleymills 0:04990d454f45 442
ashleymills 0:04990d454f45 443 dtls_int_to_uint24(buf, frag_length);
ashleymills 0:04990d454f45 444 buf += sizeof(uint24);
ashleymills 0:04990d454f45 445
ashleymills 0:04990d454f45 446 return buf;
ashleymills 0:04990d454f45 447 }
ashleymills 0:04990d454f45 448
ashleymills 0:04990d454f45 449 /**
ashleymills 0:04990d454f45 450 * Checks a received Client Hello message for a valid cookie. When the
ashleymills 0:04990d454f45 451 * Client Hello contains no cookie, the function fails and a Hello
ashleymills 0:04990d454f45 452 * Verify Request is sent to the peer (using the write callback function
ashleymills 0:04990d454f45 453 * registered with \p ctx). The return value is \c -1 on error, \c 0 when
ashleymills 0:04990d454f45 454 * undecided, and \c 1 if the Client Hello was good.
ashleymills 0:04990d454f45 455 *
ashleymills 0:04990d454f45 456 * \param ctx The DTLS context.
ashleymills 0:04990d454f45 457 * \param peer The remote party we are talking to, if any.
ashleymills 0:04990d454f45 458 * \param session Transport address of the remote peer.
ashleymills 0:04990d454f45 459 * \param msg The received datagram.
ashleymills 0:04990d454f45 460 * \param msglen Length of \p msg.
ashleymills 0:04990d454f45 461 * \return \c 1 if msg is a Client Hello with a valid cookie, \c 0 or
ashleymills 0:04990d454f45 462 * \c -1 otherwise.
ashleymills 0:04990d454f45 463 */
ashleymills 0:04990d454f45 464 int
ashleymills 0:04990d454f45 465 dtls_verify_peer(dtls_context_t *ctx,
ashleymills 0:04990d454f45 466 dtls_peer_t *peer,
ashleymills 0:04990d454f45 467 session_t *session,
ashleymills 0:04990d454f45 468 uint8 *record,
ashleymills 0:04990d454f45 469 uint8 *data, size_t data_length) {
ashleymills 1:bc8a649bad13 470 DBG("Entering dtls_verify_peer");
ashleymills 0:04990d454f45 471 int len = DTLS_COOKIE_LENGTH;
ashleymills 0:04990d454f45 472 uint8 *cookie, *p;
ashleymills 0:04990d454f45 473 #undef mycookie
ashleymills 0:04990d454f45 474 #define mycookie (ctx->sendbuf + HV_HDR_LENGTH)
ashleymills 0:04990d454f45 475
ashleymills 0:04990d454f45 476 /* check if we can access at least all fields from the handshake header */
ashleymills 0:04990d454f45 477 DBG("record[0]: %d, (%d) data_length: %d (%d), data[0]: %d (%d)\r\n",
ashleymills 0:04990d454f45 478 record[0],DTLS_CT_HANDSHAKE,data_length,DTLS_HS_LENGTH,data[0],DTLS_HT_CLIENT_HELLO);
ashleymills 0:04990d454f45 479
ashleymills 0:04990d454f45 480 if (record[0] == DTLS_CT_HANDSHAKE
ashleymills 0:04990d454f45 481 && data_length >= DTLS_HS_LENGTH
ashleymills 0:04990d454f45 482 && data[0] == DTLS_HT_CLIENT_HELLO) {
ashleymills 0:04990d454f45 483
ashleymills 0:04990d454f45 484 /* Store cookie where we can reuse it for the HelloVerify request. */
ashleymills 0:04990d454f45 485 if (dtls_create_cookie(ctx, session, data, data_length,mycookie, &len) < 0) {
ashleymills 1:bc8a649bad13 486 DBG("Cannot create cookie");
ashleymills 0:04990d454f45 487 return -1;
ashleymills 0:04990d454f45 488 }
ashleymills 0:04990d454f45 489 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 490 /* DBG("create cookie: "); */
ashleymills 0:04990d454f45 491 /* dump(mycookie, len); */
ashleymills 0:04990d454f45 492 /* printf("\n"); */
ashleymills 0:04990d454f45 493 /* #endif */
ashleymills 0:04990d454f45 494 assert(len == DTLS_COOKIE_LENGTH);
ashleymills 0:04990d454f45 495
ashleymills 0:04990d454f45 496 /* Perform cookie check. */
ashleymills 0:04990d454f45 497 len = dtls_get_cookie(data, data_length, &cookie);
ashleymills 0:04990d454f45 498
ashleymills 0:04990d454f45 499 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 500 /* DBG("compare with cookie: "); */
ashleymills 0:04990d454f45 501 /* dump(cookie, len); */
ashleymills 0:04990d454f45 502 /* printf("\n"); */
ashleymills 0:04990d454f45 503 /* #endif */
ashleymills 0:04990d454f45 504
ashleymills 0:04990d454f45 505 /* check if cookies match */
ashleymills 0:04990d454f45 506 if (len == DTLS_COOKIE_LENGTH && memcmp(cookie, mycookie, len) == 0) {
ashleymills 1:bc8a649bad13 507 DBG("Found matching cookie");
ashleymills 0:04990d454f45 508 return 1;
ashleymills 0:04990d454f45 509 }
ashleymills 0:04990d454f45 510 if (len > 0) {
ashleymills 0:04990d454f45 511 DBG("invalid cookie");
ashleymills 0:04990d454f45 512 #ifndef NDEBUG
ashleymills 0:04990d454f45 513 dump(cookie, len);
ashleymills 1:bc8a649bad13 514 DBGX("\r\n");
ashleymills 0:04990d454f45 515 #endif
ashleymills 0:04990d454f45 516 }
ashleymills 0:04990d454f45 517 /* ClientHello did not contain any valid cookie, hence we send a
ashleymills 0:04990d454f45 518 * HelloVerify request. */
ashleymills 0:04990d454f45 519
ashleymills 0:04990d454f45 520 p = dtls_set_handshake_header(DTLS_HT_HELLO_VERIFY_REQUEST,
ashleymills 0:04990d454f45 521 peer, DTLS_HV_LENGTH + DTLS_COOKIE_LENGTH,
ashleymills 0:04990d454f45 522 0, DTLS_HV_LENGTH + DTLS_COOKIE_LENGTH,
ashleymills 0:04990d454f45 523 ctx->sendbuf + DTLS_RH_LENGTH);
ashleymills 0:04990d454f45 524
ashleymills 0:04990d454f45 525 dtls_int_to_uint16(p, DTLS_VERSION);
ashleymills 0:04990d454f45 526 p += sizeof(uint16);
ashleymills 0:04990d454f45 527
ashleymills 0:04990d454f45 528 dtls_int_to_uint8(p, DTLS_COOKIE_LENGTH);
ashleymills 0:04990d454f45 529 p += sizeof(uint8);
ashleymills 0:04990d454f45 530
ashleymills 0:04990d454f45 531 assert(p == mycookie);
ashleymills 0:04990d454f45 532
ashleymills 0:04990d454f45 533 p += DTLS_COOKIE_LENGTH;
ashleymills 0:04990d454f45 534
ashleymills 0:04990d454f45 535 if (!peer) {
ashleymills 0:04990d454f45 536 /* It's an initial ClientHello, so we set the record header
ashleymills 0:04990d454f45 537 * manually and send the HelloVerify request using the
ashleymills 0:04990d454f45 538 * registered write callback. */
ashleymills 0:04990d454f45 539
ashleymills 0:04990d454f45 540 dtls_set_record_header(DTLS_CT_HANDSHAKE, NULL, ctx->sendbuf);
ashleymills 0:04990d454f45 541 /* set packet length */
ashleymills 0:04990d454f45 542 dtls_int_to_uint16(ctx->sendbuf + 11,
ashleymills 0:04990d454f45 543 p - (ctx->sendbuf + DTLS_RH_LENGTH));
ashleymills 0:04990d454f45 544
ashleymills 0:04990d454f45 545 (void)CALL(ctx, write, session, ctx->sendbuf, p - ctx->sendbuf);
ashleymills 0:04990d454f45 546 } else {
ashleymills 0:04990d454f45 547 if (peer->epoch) {
ashleymills 0:04990d454f45 548 DBG("renegotiation, therefore we accept it anyway:");
ashleymills 0:04990d454f45 549 return 1;
ashleymills 0:04990d454f45 550 }
ashleymills 0:04990d454f45 551
ashleymills 0:04990d454f45 552 if (dtls_send(ctx, peer, DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 553 ctx->sendbuf + DTLS_RH_LENGTH,
ashleymills 0:04990d454f45 554 p - (ctx->sendbuf + DTLS_RH_LENGTH)) < 0) {
ashleymills 1:bc8a649bad13 555 WARN("Cannot send HelloVerify request");
ashleymills 0:04990d454f45 556 return -1;
ashleymills 0:04990d454f45 557 }
ashleymills 0:04990d454f45 558 }
ashleymills 0:04990d454f45 559
ashleymills 0:04990d454f45 560 return 0; /* HelloVerify is sent, now we cannot do anything but wait */
ashleymills 0:04990d454f45 561 }
ashleymills 1:bc8a649bad13 562 DBG("Not a ClientHello, signal error");
ashleymills 0:04990d454f45 563 return -1; /* not a ClientHello, signal error */
ashleymills 0:04990d454f45 564 #undef mycookie
ashleymills 0:04990d454f45 565 }
ashleymills 0:04990d454f45 566
ashleymills 0:04990d454f45 567 /** only one compression method is currently defined */
ashleymills 0:04990d454f45 568 uint8 compression_methods[] = {
ashleymills 0:04990d454f45 569 TLS_COMP_NULL
ashleymills 0:04990d454f45 570 };
ashleymills 0:04990d454f45 571
ashleymills 0:04990d454f45 572 /**
ashleymills 0:04990d454f45 573 * Returns @c 1 if @p code is a cipher suite other than @c
ashleymills 0:04990d454f45 574 * TLS_NULL_WITH_NULL_NULL that we recognize.
ashleymills 0:04990d454f45 575 *
ashleymills 0:04990d454f45 576 * @param code The cipher suite identifier to check
ashleymills 0:04990d454f45 577 * @return @c 1 iff @p code is recognized,
ashleymills 0:04990d454f45 578 */
ashleymills 0:04990d454f45 579 static inline int
ashleymills 0:04990d454f45 580 known_cipher(dtls_cipher_t code) {
ashleymills 0:04990d454f45 581 return code == TLS_PSK_WITH_AES_128_CCM_8;
ashleymills 0:04990d454f45 582 }
ashleymills 0:04990d454f45 583
ashleymills 0:04990d454f45 584 int
ashleymills 0:04990d454f45 585 calculate_key_block(dtls_context_t *ctx,
ashleymills 0:04990d454f45 586 dtls_security_parameters_t *config,
ashleymills 0:04990d454f45 587 const dtls_key_t *key,
ashleymills 0:04990d454f45 588 unsigned char client_random[32],
ashleymills 0:04990d454f45 589 unsigned char server_random[32]) {
ashleymills 0:04990d454f45 590 unsigned char *pre_master_secret;
ashleymills 0:04990d454f45 591 size_t pre_master_len = 0;
ashleymills 0:04990d454f45 592 pre_master_secret = config->key_block;
ashleymills 0:04990d454f45 593
ashleymills 0:04990d454f45 594 assert(key);
ashleymills 0:04990d454f45 595 switch (key->type) {
ashleymills 0:04990d454f45 596 case DTLS_KEY_PSK: {
ashleymills 0:04990d454f45 597 /* Temporarily use the key_block storage space for the pre master secret. */
ashleymills 0:04990d454f45 598 pre_master_len = dtls_pre_master_secret(key->key.psk.key, key->key.psk.key_length,
ashleymills 0:04990d454f45 599 pre_master_secret);
ashleymills 0:04990d454f45 600
ashleymills 0:04990d454f45 601 break;
ashleymills 0:04990d454f45 602 }
ashleymills 0:04990d454f45 603 default:
ashleymills 1:bc8a649bad13 604 DBG("Calculate_key_block: unknown key type");
ashleymills 0:04990d454f45 605 return 0;
ashleymills 0:04990d454f45 606 }
ashleymills 0:04990d454f45 607
ashleymills 0:04990d454f45 608 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 609 /* { */
ashleymills 0:04990d454f45 610 /* int i; */
ashleymills 0:04990d454f45 611
ashleymills 0:04990d454f45 612 /* printf("client_random:"); */
ashleymills 0:04990d454f45 613 /* for (i = 0; i < 32; ++i) */
ashleymills 0:04990d454f45 614 /* printf(" %02x", client_random[i]); */
ashleymills 0:04990d454f45 615 /* printf("\n"); */
ashleymills 0:04990d454f45 616
ashleymills 0:04990d454f45 617 /* printf("server_random:"); */
ashleymills 0:04990d454f45 618 /* for (i = 0; i < 32; ++i) */
ashleymills 0:04990d454f45 619 /* printf(" %02x", server_random[i]); */
ashleymills 0:04990d454f45 620 /* printf("\n"); */
ashleymills 0:04990d454f45 621
ashleymills 0:04990d454f45 622 /* printf("psk: (%lu bytes):", key->key.psk.key_length); */
ashleymills 0:04990d454f45 623 /* hexdump(key->key.psk.key, key->key.psk.key_length); */
ashleymills 0:04990d454f45 624 /* printf("\n"); */
ashleymills 0:04990d454f45 625
ashleymills 0:04990d454f45 626 /* printf("pre_master_secret: (%lu bytes):", pre_master_len); */
ashleymills 0:04990d454f45 627 /* for (i = 0; i < pre_master_len; ++i) */
ashleymills 0:04990d454f45 628 /* printf(" %02x", pre_master_secret[i]); */
ashleymills 0:04990d454f45 629 /* printf("\n"); */
ashleymills 0:04990d454f45 630 /* } */
ashleymills 0:04990d454f45 631 /* #endif /\* NDEBUG *\/ */
ashleymills 0:04990d454f45 632
ashleymills 0:04990d454f45 633 dtls_prf(pre_master_secret, pre_master_len,
ashleymills 0:04990d454f45 634 PRF_LABEL(master), PRF_LABEL_SIZE(master),
ashleymills 0:04990d454f45 635 client_random, 32,
ashleymills 0:04990d454f45 636 server_random, 32,
ashleymills 0:04990d454f45 637 config->master_secret,
ashleymills 0:04990d454f45 638 DTLS_MASTER_SECRET_LENGTH);
ashleymills 0:04990d454f45 639
ashleymills 0:04990d454f45 640 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 641 /* { */
ashleymills 0:04990d454f45 642 /* int i; */
ashleymills 0:04990d454f45 643 /* printf("master_secret (%d bytes):", DTLS_MASTER_SECRET_LENGTH); */
ashleymills 0:04990d454f45 644 /* for (i = 0; i < DTLS_MASTER_SECRET_LENGTH; ++i) */
ashleymills 0:04990d454f45 645 /* printf(" %02x", config->master_secret[i]); */
ashleymills 0:04990d454f45 646 /* printf("\n"); */
ashleymills 0:04990d454f45 647 /* } */
ashleymills 0:04990d454f45 648 /* #endif /\* NDEBUG *\/ */
ashleymills 0:04990d454f45 649
ashleymills 0:04990d454f45 650 /* create key_block from master_secret
ashleymills 0:04990d454f45 651 * key_block = PRF(master_secret,
ashleymills 0:04990d454f45 652 "key expansion" + server_random + client_random) */
ashleymills 0:04990d454f45 653
ashleymills 0:04990d454f45 654 dtls_prf(config->master_secret,
ashleymills 0:04990d454f45 655 DTLS_MASTER_SECRET_LENGTH,
ashleymills 0:04990d454f45 656 PRF_LABEL(key), PRF_LABEL_SIZE(key),
ashleymills 0:04990d454f45 657 server_random, 32,
ashleymills 0:04990d454f45 658 client_random, 32,
ashleymills 0:04990d454f45 659 config->key_block,
ashleymills 0:04990d454f45 660 dtls_kb_size(config));
ashleymills 0:04990d454f45 661
ashleymills 0:04990d454f45 662 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 663 /* { */
ashleymills 0:04990d454f45 664 /* printf("key_block (%d bytes):\n", dtls_kb_size(config)); */
ashleymills 0:04990d454f45 665 /* printf(" client_MAC_secret:\t"); */
ashleymills 0:04990d454f45 666 /* dump(dtls_kb_client_mac_secret(config), */
ashleymills 0:04990d454f45 667 /* dtls_kb_mac_secret_size(config)); */
ashleymills 0:04990d454f45 668 /* printf("\n"); */
ashleymills 0:04990d454f45 669
ashleymills 0:04990d454f45 670 /* printf(" server_MAC_secret:\t"); */
ashleymills 0:04990d454f45 671 /* dump(dtls_kb_server_mac_secret(config), */
ashleymills 0:04990d454f45 672 /* dtls_kb_mac_secret_size(config)); */
ashleymills 0:04990d454f45 673 /* printf("\n"); */
ashleymills 0:04990d454f45 674
ashleymills 0:04990d454f45 675 /* printf(" client_write_key:\t"); */
ashleymills 0:04990d454f45 676 /* dump(dtls_kb_client_write_key(config), */
ashleymills 0:04990d454f45 677 /* dtls_kb_key_size(config)); */
ashleymills 0:04990d454f45 678 /* printf("\n"); */
ashleymills 0:04990d454f45 679
ashleymills 0:04990d454f45 680 /* printf(" server_write_key:\t"); */
ashleymills 0:04990d454f45 681 /* dump(dtls_kb_server_write_key(config), */
ashleymills 0:04990d454f45 682 /* dtls_kb_key_size(config)); */
ashleymills 0:04990d454f45 683 /* printf("\n"); */
ashleymills 0:04990d454f45 684
ashleymills 0:04990d454f45 685 /* printf(" client_IV:\t\t"); */
ashleymills 0:04990d454f45 686 /* dump(dtls_kb_client_iv(config), */
ashleymills 0:04990d454f45 687 /* dtls_kb_iv_size(config)); */
ashleymills 0:04990d454f45 688 /* printf("\n"); */
ashleymills 0:04990d454f45 689
ashleymills 0:04990d454f45 690 /* printf(" server_IV:\t\t"); */
ashleymills 0:04990d454f45 691 /* dump(dtls_kb_server_iv(config), */
ashleymills 0:04990d454f45 692 /* dtls_kb_iv_size(config)); */
ashleymills 0:04990d454f45 693 /* printf("\n"); */
ashleymills 0:04990d454f45 694
ashleymills 0:04990d454f45 695
ashleymills 0:04990d454f45 696 /* } */
ashleymills 0:04990d454f45 697 /* #endif */
ashleymills 0:04990d454f45 698 return 1;
ashleymills 0:04990d454f45 699 }
ashleymills 0:04990d454f45 700
ashleymills 0:04990d454f45 701 /**
ashleymills 0:04990d454f45 702 * Updates the security parameters of given \p peer. As this must be
ashleymills 0:04990d454f45 703 * done before the new configuration is activated, it changes the
ashleymills 0:04990d454f45 704 * OTHER_CONFIG only. When the ClientHello handshake message in \p
ashleymills 0:04990d454f45 705 * data does not contain a cipher suite or compression method, it is
ashleymills 0:04990d454f45 706 * copied from the CURRENT_CONFIG.
ashleymills 0:04990d454f45 707 *
ashleymills 0:04990d454f45 708 * \param ctx The current DTLS context.
ashleymills 0:04990d454f45 709 * \param peer The remote peer whose security parameters are about to change.
ashleymills 0:04990d454f45 710 * \param data The handshake message with a ClientHello.
ashleymills 0:04990d454f45 711 * \param data_length The actual size of \p data.
ashleymills 0:04990d454f45 712 * \return \c 0 if an error occurred, \c 1 otherwise.
ashleymills 0:04990d454f45 713 */
ashleymills 0:04990d454f45 714 int
ashleymills 0:04990d454f45 715 dtls_update_parameters(dtls_context_t *ctx,
ashleymills 0:04990d454f45 716 dtls_peer_t *peer,
ashleymills 0:04990d454f45 717 uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 718 int i, j;
ashleymills 0:04990d454f45 719 int ok;
ashleymills 0:04990d454f45 720 dtls_security_parameters_t *config = OTHER_CONFIG(peer);
ashleymills 0:04990d454f45 721
ashleymills 0:04990d454f45 722 assert(config);
ashleymills 0:04990d454f45 723 assert(data_length > DTLS_HS_LENGTH + DTLS_CH_LENGTH);
ashleymills 0:04990d454f45 724
ashleymills 0:04990d454f45 725 /* DBG("dtls_update_parameters: msglen is %d\n", data_length); */
ashleymills 0:04990d454f45 726
ashleymills 0:04990d454f45 727 /* skip the handshake header and client version INFOrmation */
ashleymills 0:04990d454f45 728 data += DTLS_HS_LENGTH + sizeof(uint16);
ashleymills 0:04990d454f45 729 data_length -= DTLS_HS_LENGTH + sizeof(uint16);
ashleymills 0:04990d454f45 730
ashleymills 0:04990d454f45 731 /* store client random in config
ashleymills 0:04990d454f45 732 * FIXME: if we send the ServerHello here, we do not need to store
ashleymills 0:04990d454f45 733 * the client's random bytes */
ashleymills 0:04990d454f45 734 memcpy(config->client_random, data, sizeof(config->client_random));
ashleymills 0:04990d454f45 735 data += sizeof(config->client_random);
ashleymills 0:04990d454f45 736 data_length -= sizeof(config->client_random);
ashleymills 0:04990d454f45 737
ashleymills 0:04990d454f45 738 /* Caution: SKIP_VAR_FIELD may jump to error: */
ashleymills 0:04990d454f45 739 SKIP_VAR_FIELD(data, data_length, uint8); /* skip session id */
ashleymills 0:04990d454f45 740 SKIP_VAR_FIELD(data, data_length, uint8); /* skip cookie */
ashleymills 0:04990d454f45 741
ashleymills 0:04990d454f45 742 i = dtls_uint16_to_int(data);
ashleymills 0:04990d454f45 743 if (data_length < i + sizeof(uint16)) {
ashleymills 0:04990d454f45 744 /* Looks like we do not have a cipher nor compression. This is ok
ashleymills 0:04990d454f45 745 * for renegotiation, but not for the initial handshake. */
ashleymills 0:04990d454f45 746
ashleymills 0:04990d454f45 747 if (CURRENT_CONFIG(peer)->cipher == TLS_NULL_WITH_NULL_NULL)
ashleymills 0:04990d454f45 748 goto error;
ashleymills 0:04990d454f45 749
ashleymills 0:04990d454f45 750 config->cipher = CURRENT_CONFIG(peer)->cipher;
ashleymills 0:04990d454f45 751 config->compression = CURRENT_CONFIG(peer)->compression;
ashleymills 0:04990d454f45 752
ashleymills 0:04990d454f45 753 return 1;
ashleymills 0:04990d454f45 754 }
ashleymills 0:04990d454f45 755
ashleymills 0:04990d454f45 756 data += sizeof(uint16);
ashleymills 0:04990d454f45 757 data_length -= sizeof(uint16) + i;
ashleymills 0:04990d454f45 758
ashleymills 0:04990d454f45 759 ok = 0;
ashleymills 0:04990d454f45 760 while (i && !ok) {
ashleymills 0:04990d454f45 761 config->cipher = dtls_uint16_to_int(data);
ashleymills 0:04990d454f45 762 ok = known_cipher(config->cipher);
ashleymills 0:04990d454f45 763 i -= sizeof(uint16);
ashleymills 0:04990d454f45 764 data += sizeof(uint16);
ashleymills 0:04990d454f45 765 }
ashleymills 0:04990d454f45 766
ashleymills 0:04990d454f45 767 /* skip remaining ciphers */
ashleymills 0:04990d454f45 768 data += i;
ashleymills 0:04990d454f45 769
ashleymills 0:04990d454f45 770 if (!ok) {
ashleymills 0:04990d454f45 771 /* reset config cipher to a well-defined value */
ashleymills 0:04990d454f45 772 config->cipher = TLS_NULL_WITH_NULL_NULL;
ashleymills 0:04990d454f45 773 return 0;
ashleymills 0:04990d454f45 774 }
ashleymills 0:04990d454f45 775
ashleymills 0:04990d454f45 776 if (data_length < sizeof(uint8)) {
ashleymills 0:04990d454f45 777 /* no compression specified, take the current compression method */
ashleymills 0:04990d454f45 778 config->compression = CURRENT_CONFIG(peer)->compression;
ashleymills 0:04990d454f45 779 return 1;
ashleymills 0:04990d454f45 780 }
ashleymills 0:04990d454f45 781
ashleymills 0:04990d454f45 782 i = dtls_uint8_to_int(data);
ashleymills 0:04990d454f45 783 if (data_length < i + sizeof(uint8))
ashleymills 0:04990d454f45 784 goto error;
ashleymills 0:04990d454f45 785
ashleymills 0:04990d454f45 786 data += sizeof(uint8);
ashleymills 0:04990d454f45 787 data_length -= sizeof(uint8) + i;
ashleymills 0:04990d454f45 788
ashleymills 0:04990d454f45 789 ok = 0;
ashleymills 0:04990d454f45 790 while (i && !ok) {
ashleymills 0:04990d454f45 791 for (j = 0; j < sizeof(compression_methods) / sizeof(uint8); ++j)
ashleymills 0:04990d454f45 792 if (dtls_uint8_to_int(data) == compression_methods[j]) {
ashleymills 0:04990d454f45 793 config->compression = compression_methods[j];
ashleymills 0:04990d454f45 794 ok = 1;
ashleymills 0:04990d454f45 795 }
ashleymills 0:04990d454f45 796 i -= sizeof(uint8);
ashleymills 0:04990d454f45 797 data += sizeof(uint8);
ashleymills 0:04990d454f45 798 }
ashleymills 0:04990d454f45 799
ashleymills 0:04990d454f45 800 return ok;
ashleymills 0:04990d454f45 801 error:
ashleymills 1:bc8a649bad13 802 WARN("ClientHello too short (%d bytes)", data_length);
ashleymills 0:04990d454f45 803 return 0;
ashleymills 0:04990d454f45 804 }
ashleymills 0:04990d454f45 805
ashleymills 0:04990d454f45 806 static inline int
ashleymills 0:04990d454f45 807 check_client_keyexchange(dtls_context_t *ctx,
ashleymills 0:04990d454f45 808 dtls_peer_t *peer,
ashleymills 0:04990d454f45 809 uint8 *data, size_t length) {
ashleymills 0:04990d454f45 810 return length >= DTLS_CKX_LENGTH && data[0] == DTLS_HT_CLIENT_KEY_EXCHANGE;
ashleymills 0:04990d454f45 811 }
ashleymills 0:04990d454f45 812
ashleymills 0:04990d454f45 813 static int
ashleymills 0:04990d454f45 814 check_ccs(dtls_context_t *ctx,
ashleymills 0:04990d454f45 815 dtls_peer_t *peer,
ashleymills 0:04990d454f45 816 uint8 *record, uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 817
ashleymills 0:04990d454f45 818 if (DTLS_RECORD_HEADER(record)->content_type != DTLS_CT_CHANGE_CIPHER_SPEC
ashleymills 0:04990d454f45 819 || data_length < 1 || data[0] != 1)
ashleymills 0:04990d454f45 820 return 0;
ashleymills 0:04990d454f45 821
ashleymills 0:04990d454f45 822 /* set crypto context for TLS_PSK_WITH_AES_128_CCM_8 */
ashleymills 0:04990d454f45 823 /* client */
ashleymills 0:04990d454f45 824 dtls_cipher_free(OTHER_CONFIG(peer)->read_cipher);
ashleymills 0:04990d454f45 825
ashleymills 0:04990d454f45 826 assert(OTHER_CONFIG(peer)->cipher != TLS_NULL_WITH_NULL_NULL);
ashleymills 0:04990d454f45 827 OTHER_CONFIG(peer)->read_cipher =
ashleymills 0:04990d454f45 828 dtls_cipher_new(OTHER_CONFIG(peer)->cipher,
ashleymills 0:04990d454f45 829 dtls_kb_client_write_key(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 830 dtls_kb_key_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 831
ashleymills 0:04990d454f45 832 if (!OTHER_CONFIG(peer)->read_cipher) {
ashleymills 1:bc8a649bad13 833 WARN("Cannot create read cipher");
ashleymills 0:04990d454f45 834 return 0;
ashleymills 0:04990d454f45 835 }
ashleymills 0:04990d454f45 836
ashleymills 0:04990d454f45 837 dtls_cipher_set_iv(OTHER_CONFIG(peer)->read_cipher,
ashleymills 0:04990d454f45 838 dtls_kb_client_iv(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 839 dtls_kb_iv_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 840
ashleymills 0:04990d454f45 841 /* server */
ashleymills 0:04990d454f45 842 dtls_cipher_free(OTHER_CONFIG(peer)->write_cipher);
ashleymills 0:04990d454f45 843
ashleymills 0:04990d454f45 844 OTHER_CONFIG(peer)->write_cipher =
ashleymills 0:04990d454f45 845 dtls_cipher_new(OTHER_CONFIG(peer)->cipher,
ashleymills 0:04990d454f45 846 dtls_kb_server_write_key(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 847 dtls_kb_key_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 848
ashleymills 0:04990d454f45 849 if (!OTHER_CONFIG(peer)->write_cipher) {
ashleymills 1:bc8a649bad13 850 WARN("Cannot create write cipher");
ashleymills 0:04990d454f45 851 return 0;
ashleymills 0:04990d454f45 852 }
ashleymills 0:04990d454f45 853
ashleymills 0:04990d454f45 854 dtls_cipher_set_iv(OTHER_CONFIG(peer)->write_cipher,
ashleymills 0:04990d454f45 855 dtls_kb_server_iv(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 856 dtls_kb_iv_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 857
ashleymills 0:04990d454f45 858 return 1;
ashleymills 0:04990d454f45 859 }
ashleymills 0:04990d454f45 860
ashleymills 0:04990d454f45 861 #ifndef NDEBUG
ashleymills 0:04990d454f45 862 extern size_t dsrv_print_addr(const session_t *, unsigned char *, size_t);
ashleymills 0:04990d454f45 863 #endif
ashleymills 0:04990d454f45 864
ashleymills 0:04990d454f45 865 static inline void
ashleymills 0:04990d454f45 866 update_hs_hash(dtls_peer_t *peer, uint8 *data, size_t length) {
ashleymills 0:04990d454f45 867 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 868 /* printf("add MAC data: "); */
ashleymills 0:04990d454f45 869 /* dump(data, length); */
ashleymills 0:04990d454f45 870 /* printf("\n"); */
ashleymills 0:04990d454f45 871 /* #endif */
ashleymills 0:04990d454f45 872 dtls_hash_update(&peer->hs_state.hs_hash, data, length);
ashleymills 0:04990d454f45 873 }
ashleymills 0:04990d454f45 874
ashleymills 0:04990d454f45 875 static inline size_t
ashleymills 0:04990d454f45 876 finalize_hs_hash(dtls_peer_t *peer, uint8 *buf) {
ashleymills 0:04990d454f45 877 return dtls_hash_finalize(buf, &peer->hs_state.hs_hash);
ashleymills 0:04990d454f45 878 }
ashleymills 0:04990d454f45 879
ashleymills 0:04990d454f45 880 static inline void
ashleymills 0:04990d454f45 881 clear_hs_hash(dtls_peer_t *peer) {
ashleymills 0:04990d454f45 882 assert(peer);
ashleymills 0:04990d454f45 883 dtls_hash_init(&peer->hs_state.hs_hash);
ashleymills 0:04990d454f45 884 }
ashleymills 0:04990d454f45 885
ashleymills 0:04990d454f45 886 /**
ashleymills 0:04990d454f45 887 *Checks if \p record + \p data contain a Finished message with valid
ashleymills 0:04990d454f45 888 * verify_data.
ashleymills 0:04990d454f45 889 *
ashleymills 0:04990d454f45 890 * \param ctx The current DTLS context.
ashleymills 0:04990d454f45 891 * \param peer The remote peer of the security association.
ashleymills 0:04990d454f45 892 * \param record The message record header.
ashleymills 0:04990d454f45 893 * \param rlen The actual length of \p record.
ashleymills 0:04990d454f45 894 * \param data The cleartext payload of the message.
ashleymills 0:04990d454f45 895 * \param data_length Actual length of \p data.
ashleymills 0:04990d454f45 896 * \return \c 1 if the Finished message is valid, \c 0 otherwise.
ashleymills 0:04990d454f45 897 */
ashleymills 0:04990d454f45 898 static int
ashleymills 0:04990d454f45 899 check_finished(dtls_context_t *ctx, dtls_peer_t *peer,
ashleymills 0:04990d454f45 900 uint8 *record, uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 901 size_t digest_length, label_size;
ashleymills 0:04990d454f45 902 const unsigned char *label;
ashleymills 0:04990d454f45 903 unsigned char buf[DTLS_HMAC_MAX];
ashleymills 0:04990d454f45 904
ashleymills 0:04990d454f45 905 /* Use a union here to ensure that sufficient stack space is
ashleymills 0:04990d454f45 906 * reserved. As statebuf and verify_data are not used at the same
ashleymills 0:04990d454f45 907 * time, we can re-use the storage safely.
ashleymills 0:04990d454f45 908 */
ashleymills 0:04990d454f45 909 union {
ashleymills 0:04990d454f45 910 unsigned char statebuf[DTLS_HASH_CTX_SIZE];
ashleymills 0:04990d454f45 911 unsigned char verify_data[DTLS_FIN_LENGTH];
ashleymills 0:04990d454f45 912 } b;
ashleymills 0:04990d454f45 913
ashleymills 1:bc8a649bad13 914 DBG("Check Finish message");
ashleymills 1:bc8a649bad13 915 if(record[0] != DTLS_CT_HANDSHAKE || !IS_FINISHED(data, data_length)) {
ashleymills 1:bc8a649bad13 916 DBG("Failed");
ashleymills 0:04990d454f45 917 return 0;
ashleymills 0:04990d454f45 918 }
ashleymills 0:04990d454f45 919
ashleymills 0:04990d454f45 920 /* temporarily store hash status for roll-back after finalize */
ashleymills 0:04990d454f45 921 memcpy(b.statebuf, &peer->hs_state.hs_hash, DTLS_HASH_CTX_SIZE);
ashleymills 0:04990d454f45 922
ashleymills 0:04990d454f45 923 digest_length = finalize_hs_hash(peer, buf);
ashleymills 0:04990d454f45 924 /* clear_hash(); */
ashleymills 0:04990d454f45 925
ashleymills 0:04990d454f45 926 /* restore hash status */
ashleymills 0:04990d454f45 927 memcpy(&peer->hs_state.hs_hash, b.statebuf, DTLS_HASH_CTX_SIZE);
ashleymills 0:04990d454f45 928
ashleymills 0:04990d454f45 929 if (CURRENT_CONFIG(peer)->role == DTLS_SERVER) {
ashleymills 0:04990d454f45 930 label = PRF_LABEL(server);
ashleymills 0:04990d454f45 931 label_size = PRF_LABEL_SIZE(server);
ashleymills 0:04990d454f45 932 } else { /* client */
ashleymills 0:04990d454f45 933 label = PRF_LABEL(client);
ashleymills 0:04990d454f45 934 label_size = PRF_LABEL_SIZE(client);
ashleymills 0:04990d454f45 935 }
ashleymills 0:04990d454f45 936
ashleymills 0:04990d454f45 937 dtls_prf(CURRENT_CONFIG(peer)->master_secret,
ashleymills 0:04990d454f45 938 DTLS_MASTER_SECRET_LENGTH,
ashleymills 0:04990d454f45 939 label, label_size,
ashleymills 0:04990d454f45 940 PRF_LABEL(finished), PRF_LABEL_SIZE(finished),
ashleymills 0:04990d454f45 941 buf, digest_length,
ashleymills 0:04990d454f45 942 b.verify_data, sizeof(b.verify_data));
ashleymills 0:04990d454f45 943
ashleymills 0:04990d454f45 944 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 945 /* printf("d:\t"); dump(data + DTLS_HS_LENGTH, sizeof(b.verify_data)); printf("\n"); */
ashleymills 0:04990d454f45 946 /* printf("v:\t"); dump(b.verify_data, sizeof(b.verify_data)); printf("\n"); */
ashleymills 0:04990d454f45 947 /* #endif */
ashleymills 0:04990d454f45 948 return
ashleymills 0:04990d454f45 949 memcmp(data + DTLS_HS_LENGTH, b.verify_data, sizeof(b.verify_data)) == 0;
ashleymills 0:04990d454f45 950 }
ashleymills 0:04990d454f45 951
ashleymills 0:04990d454f45 952 /**
ashleymills 0:04990d454f45 953 * Prepares the payload given in \p data for sending with
ashleymills 0:04990d454f45 954 * dtls_send(). The \p data is encrypted and compressed according to
ashleymills 0:04990d454f45 955 * the current security parameters of \p peer. The result of this
ashleymills 0:04990d454f45 956 * operation is put into \p sendbuf with a prepended record header of
ashleymills 0:04990d454f45 957 * type \p type ready for sending. As some cipher suites add a MAC
ashleymills 0:04990d454f45 958 * before encryption, \p data must be large enough to hold this data
ashleymills 0:04990d454f45 959 * as well (usually \c dtls_kb_digest_size(CURRENT_CONFIG(peer)).
ashleymills 0:04990d454f45 960 *
ashleymills 0:04990d454f45 961 * \param peer The remote peer the packet will be sent to.
ashleymills 0:04990d454f45 962 * \param type The content type of this record.
ashleymills 0:04990d454f45 963 * \param data The payload to send.
ashleymills 0:04990d454f45 964 * \param data_length The size of \p data.
ashleymills 0:04990d454f45 965 * \param sendbuf The output buffer where the encrypted record
ashleymills 0:04990d454f45 966 * will be placed.
ashleymills 0:04990d454f45 967 * \param rlen This parameter must be initialized with the
ashleymills 0:04990d454f45 968 * maximum size of \p sendbuf and will be updated
ashleymills 0:04990d454f45 969 * to hold the actual size of the stored packet
ashleymills 0:04990d454f45 970 * on success. On error, the value of \p rlen is
ashleymills 0:04990d454f45 971 * undefined.
ashleymills 0:04990d454f45 972 * \return Less than zero on error, or greater than zero success.
ashleymills 0:04990d454f45 973 */
ashleymills 0:04990d454f45 974 int
ashleymills 0:04990d454f45 975 dtls_prepare_record(dtls_peer_t *peer,
ashleymills 0:04990d454f45 976 unsigned char type,
ashleymills 0:04990d454f45 977 uint8 *data, size_t data_length,
ashleymills 0:04990d454f45 978 uint8 *sendbuf, size_t *rlen) {
ashleymills 0:04990d454f45 979 uint8 *p;
ashleymills 0:04990d454f45 980 int res;
ashleymills 0:04990d454f45 981
ashleymills 0:04990d454f45 982 /* check the minimum that we need for packets that are not encrypted */
ashleymills 0:04990d454f45 983 if (*rlen < DTLS_RH_LENGTH + data_length) {
ashleymills 1:bc8a649bad13 984 DBG("dtls_prepare_record: send buffer too small");
ashleymills 0:04990d454f45 985 return -1;
ashleymills 0:04990d454f45 986 }
ashleymills 0:04990d454f45 987
ashleymills 0:04990d454f45 988 p = dtls_set_record_header(type, peer, sendbuf);
ashleymills 0:04990d454f45 989
ashleymills 0:04990d454f45 990 if (CURRENT_CONFIG(peer)->cipher == TLS_NULL_WITH_NULL_NULL) {
ashleymills 0:04990d454f45 991 /* no cipher suite */
ashleymills 0:04990d454f45 992 memcpy(p, data, data_length);
ashleymills 0:04990d454f45 993 res = data_length;
ashleymills 0:04990d454f45 994 } else { /* TLS_PSK_WITH_AES_128_CCM_8 */
ashleymills 0:04990d454f45 995 dtls_cipher_context_t *cipher_context;
ashleymills 0:04990d454f45 996
ashleymills 0:04990d454f45 997 /**
ashleymills 0:04990d454f45 998 * length of additional_data for the AEAD cipher which consists of
ashleymills 0:04990d454f45 999 * seq_num(2+6) + type(1) + version(2) + length(2)
ashleymills 0:04990d454f45 1000 */
ashleymills 0:04990d454f45 1001 #define A_DATA_LEN 13
ashleymills 0:04990d454f45 1002 #define A_DATA N
ashleymills 0:04990d454f45 1003 unsigned char N[max(DTLS_CCM_BLOCKSIZE, A_DATA_LEN)];
ashleymills 0:04990d454f45 1004
ashleymills 0:04990d454f45 1005 if (*rlen < sizeof(dtls_record_header_t) + data_length + 8) {
ashleymills 1:bc8a649bad13 1006 WARN("dtls_prepare_record(): send buffer too small");
ashleymills 0:04990d454f45 1007 return -1;
ashleymills 0:04990d454f45 1008 }
ashleymills 0:04990d454f45 1009
ashleymills 1:bc8a649bad13 1010 DBG("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_8");
ashleymills 0:04990d454f45 1011
ashleymills 0:04990d454f45 1012 /* set nonce
ashleymills 0:04990d454f45 1013 from http://tools.ietf.org/html/draft-mcgrew-tls-aes-ccm-03:
ashleymills 0:04990d454f45 1014 struct {
ashleymills 0:04990d454f45 1015 case client:
ashleymills 0:04990d454f45 1016 uint32 client_write_IV; // low order 32-bits
ashleymills 0:04990d454f45 1017 case server:
ashleymills 0:04990d454f45 1018 uint32 server_write_IV; // low order 32-bits
ashleymills 0:04990d454f45 1019 uint64 seq_num;
ashleymills 0:04990d454f45 1020 } CCMNonce.
ashleymills 0:04990d454f45 1021
ashleymills 0:04990d454f45 1022 In DTLS, the 64-bit seq_num is the 16-bit epoch concatenated with the
ashleymills 0:04990d454f45 1023 48-bit seq_num.
ashleymills 0:04990d454f45 1024 */
ashleymills 0:04990d454f45 1025
ashleymills 0:04990d454f45 1026 memcpy(p, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8);
ashleymills 0:04990d454f45 1027 memcpy(p + 8, data, data_length);
ashleymills 0:04990d454f45 1028
ashleymills 0:04990d454f45 1029 memset(N, 0, DTLS_CCM_BLOCKSIZE);
ashleymills 0:04990d454f45 1030 memcpy(N, dtls_kb_local_iv(CURRENT_CONFIG(peer)),
ashleymills 0:04990d454f45 1031 dtls_kb_iv_size(CURRENT_CONFIG(peer)));
ashleymills 0:04990d454f45 1032 memcpy(N + dtls_kb_iv_size(CURRENT_CONFIG(peer)), p, 8); /* epoch + seq_num */
ashleymills 0:04990d454f45 1033
ashleymills 0:04990d454f45 1034 cipher_context = CURRENT_CONFIG(peer)->write_cipher;
ashleymills 0:04990d454f45 1035
ashleymills 0:04990d454f45 1036 if (!cipher_context) {
ashleymills 1:bc8a649bad13 1037 WARN("no write_cipher available!");
ashleymills 0:04990d454f45 1038 return -1;
ashleymills 0:04990d454f45 1039 }
ashleymills 0:04990d454f45 1040 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1041 /* printf("nonce:\t"); */
ashleymills 0:04990d454f45 1042 /* dump(N, DTLS_CCM_BLOCKSIZE); */
ashleymills 0:04990d454f45 1043 /* printf("\nkey:\t"); */
ashleymills 0:04990d454f45 1044 /* dump(dtls_kb_local_write_key(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1045 /* dtls_kb_key_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1046 /* printf("\n"); */
ashleymills 0:04990d454f45 1047 /* #endif */
ashleymills 0:04990d454f45 1048 dtls_cipher_set_iv(cipher_context, N, DTLS_CCM_BLOCKSIZE);
ashleymills 0:04990d454f45 1049
ashleymills 0:04990d454f45 1050 /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3:
ashleymills 0:04990d454f45 1051 *
ashleymills 0:04990d454f45 1052 * additional_data = seq_num + TLSCompressed.type +
ashleymills 0:04990d454f45 1053 * TLSCompressed.version + TLSCompressed.length;
ashleymills 0:04990d454f45 1054 */
ashleymills 0:04990d454f45 1055 memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */
ashleymills 0:04990d454f45 1056 memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */
ashleymills 0:04990d454f45 1057 dtls_int_to_uint16(A_DATA + 11, data_length); /* length */
ashleymills 0:04990d454f45 1058
ashleymills 0:04990d454f45 1059 res = dtls_encrypt(cipher_context, p + 8, data_length, p + 8,
ashleymills 0:04990d454f45 1060 A_DATA, A_DATA_LEN);
ashleymills 0:04990d454f45 1061
ashleymills 0:04990d454f45 1062 if (res < 0)
ashleymills 0:04990d454f45 1063 return -1;
ashleymills 0:04990d454f45 1064
ashleymills 0:04990d454f45 1065 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1066 /* dump(p, res + 8); */
ashleymills 0:04990d454f45 1067 /* printf("\n"); */
ashleymills 0:04990d454f45 1068 /* #endif */
ashleymills 0:04990d454f45 1069 res += 8; /* increment res by size of nonce_explicit */
ashleymills 0:04990d454f45 1070 }
ashleymills 0:04990d454f45 1071
ashleymills 0:04990d454f45 1072 /* fix length of fragment in sendbuf */
ashleymills 0:04990d454f45 1073 dtls_int_to_uint16(sendbuf + 11, res);
ashleymills 0:04990d454f45 1074
ashleymills 0:04990d454f45 1075 *rlen = DTLS_RH_LENGTH + res;
ashleymills 0:04990d454f45 1076 return 1;
ashleymills 0:04990d454f45 1077 }
ashleymills 0:04990d454f45 1078
ashleymills 0:04990d454f45 1079 /**
ashleymills 0:04990d454f45 1080 * Returns true if the message @p Data is a handshake message that
ashleymills 0:04990d454f45 1081 * must be included in the calculation of verify_data in the Finished
ashleymills 0:04990d454f45 1082 * message.
ashleymills 0:04990d454f45 1083 *
ashleymills 0:04990d454f45 1084 * @param Type The message type. Only handshake messages but the initial
ashleymills 0:04990d454f45 1085 * Client Hello and Hello Verify Request are included in the hash,
ashleymills 0:04990d454f45 1086 * @param Data The PDU to examine.
ashleymills 0:04990d454f45 1087 * @param Length The length of @p Data.
ashleymills 0:04990d454f45 1088 *
ashleymills 0:04990d454f45 1089 * @return @c 1 if @p Data must be included in hash, @c 0 otherwise.
ashleymills 0:04990d454f45 1090 *
ashleymills 0:04990d454f45 1091 * @hideinitializer
ashleymills 0:04990d454f45 1092 */
ashleymills 0:04990d454f45 1093 #define MUST_HASH(Type, Data, Length) \
ashleymills 0:04990d454f45 1094 ((Type) == DTLS_CT_HANDSHAKE && \
ashleymills 0:04990d454f45 1095 ((Data) != NULL) && ((Length) > 0) && \
ashleymills 0:04990d454f45 1096 ((Data)[0] != DTLS_HT_HELLO_VERIFY_REQUEST) && \
ashleymills 0:04990d454f45 1097 ((Data)[0] != DTLS_HT_CLIENT_HELLO || \
ashleymills 0:04990d454f45 1098 ((Length) >= HS_HDR_LENGTH && \
ashleymills 0:04990d454f45 1099 (dtls_uint16_to_int(DTLS_RECORD_HEADER(Data)->epoch > 0) || \
ashleymills 0:04990d454f45 1100 (dtls_uint16_to_int(HANDSHAKE(Data)->message_seq) > 0)))))
ashleymills 0:04990d454f45 1101
ashleymills 0:04990d454f45 1102 /**
ashleymills 0:04990d454f45 1103 * Sends the data passed in @p buf as a DTLS record of type @p type to
ashleymills 0:04990d454f45 1104 * the given peer. The data will be encrypted and compressed according
ashleymills 0:04990d454f45 1105 * to the security parameters for @p peer.
ashleymills 0:04990d454f45 1106 *
ashleymills 0:04990d454f45 1107 * @param ctx The DTLS context in effect.
ashleymills 0:04990d454f45 1108 * @param peer The remote party where the packet is sent.
ashleymills 0:04990d454f45 1109 * @param type The content type of this record.
ashleymills 0:04990d454f45 1110 * @param buf The data to send.
ashleymills 0:04990d454f45 1111 * @param buflen The number of bytes to send from @p buf.
ashleymills 0:04990d454f45 1112 * @return Less than zero in case of an error or the number of
ashleymills 0:04990d454f45 1113 * bytes that have been sent otherwise.
ashleymills 0:04990d454f45 1114 */
ashleymills 0:04990d454f45 1115 int
ashleymills 0:04990d454f45 1116 dtls_send(dtls_context_t *ctx, dtls_peer_t *peer,
ashleymills 0:04990d454f45 1117 unsigned char type,
ashleymills 0:04990d454f45 1118 uint8 *buf, size_t buflen) {
ashleymills 0:04990d454f45 1119
ashleymills 0:04990d454f45 1120 /* We cannot use ctx->sendbuf here as it is reserved for collecting
ashleymills 0:04990d454f45 1121 * the input for this function, i.e. buf == ctx->sendbuf.
ashleymills 0:04990d454f45 1122 *
ashleymills 0:04990d454f45 1123 * TODO: check if we can use the receive buf here. This would mean
ashleymills 0:04990d454f45 1124 * that we might not be able to handle multiple records stuffed in
ashleymills 0:04990d454f45 1125 * one UDP datagram */
ashleymills 0:04990d454f45 1126 unsigned char sendbuf[DTLS_MAX_BUF];
ashleymills 0:04990d454f45 1127 size_t len = sizeof(sendbuf);
ashleymills 0:04990d454f45 1128 int res;
ashleymills 0:04990d454f45 1129
ashleymills 0:04990d454f45 1130 res = dtls_prepare_record(peer, type, buf, buflen, sendbuf, &len);
ashleymills 0:04990d454f45 1131
ashleymills 0:04990d454f45 1132 if (res < 0)
ashleymills 0:04990d454f45 1133 return res;
ashleymills 0:04990d454f45 1134
ashleymills 0:04990d454f45 1135 /* if (peer && MUST_HASH(peer, type, buf, buflen)) */
ashleymills 0:04990d454f45 1136 /* update_hs_hash(peer, buf, buflen); */
ashleymills 0:04990d454f45 1137
ashleymills 0:04990d454f45 1138 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1139 /* DBG("send %d bytes\n", buflen); */
ashleymills 0:04990d454f45 1140 /* hexdump(sendbuf, sizeof(dtls_record_header_t)); */
ashleymills 0:04990d454f45 1141 /* printf("\n"); */
ashleymills 0:04990d454f45 1142 /* hexdump(buf, buflen); */
ashleymills 0:04990d454f45 1143 /* printf("\n"); */
ashleymills 0:04990d454f45 1144 /* #endif */
ashleymills 0:04990d454f45 1145
ashleymills 0:04990d454f45 1146 if (type == DTLS_CT_HANDSHAKE && buf[0] != DTLS_HT_HELLO_VERIFY_REQUEST) {
ashleymills 0:04990d454f45 1147 /* copy handshake messages other than HelloVerify into retransmit buffer */
ashleymills 0:04990d454f45 1148 netq_t *n = netq_node_new();
ashleymills 0:04990d454f45 1149 if (n) {
ashleymills 0:04990d454f45 1150 dtls_tick_t now;
ashleymills 0:04990d454f45 1151 dtls_ticks(&now);
ashleymills 0:04990d454f45 1152 n->t = now + 2 * CLOCK_SECOND;
ashleymills 0:04990d454f45 1153 n->retransmit_cnt = 0;
ashleymills 0:04990d454f45 1154 n->timeout = 2 * CLOCK_SECOND;
ashleymills 0:04990d454f45 1155 n->peer = peer;
ashleymills 0:04990d454f45 1156 n->length = buflen;
ashleymills 0:04990d454f45 1157 memcpy(n->data, buf, buflen);
ashleymills 0:04990d454f45 1158
ashleymills 0:04990d454f45 1159 if (!netq_insert_node((netq_t **)ctx->sendqueue, n)) {
ashleymills 1:bc8a649bad13 1160 WARN("Cannot add packet to retransmit buffer");
ashleymills 0:04990d454f45 1161 netq_node_free(n);
ashleymills 0:04990d454f45 1162 #ifdef WITH_CONTIKI
ashleymills 0:04990d454f45 1163 } else {
ashleymills 0:04990d454f45 1164 /* must set timer within the context of the retransmit process */
ashleymills 0:04990d454f45 1165 PROCESS_CONTEXT_BEGIN(&dtls_retransmit_process);
ashleymills 0:04990d454f45 1166 etimer_set(&ctx->retransmit_timer, n->timeout);
ashleymills 0:04990d454f45 1167 PROCESS_CONTEXT_END(&dtls_retransmit_process);
ashleymills 0:04990d454f45 1168 #else /* WITH_CONTIKI */
ashleymills 1:bc8a649bad13 1169 DBG("Copied to sendqueue");
ashleymills 0:04990d454f45 1170 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 1171 }
ashleymills 0:04990d454f45 1172 } else
ashleymills 1:bc8a649bad13 1173 WARN("Retransmit buffer full");
ashleymills 0:04990d454f45 1174 }
ashleymills 0:04990d454f45 1175
ashleymills 0:04990d454f45 1176 /* FIXME: copy to peer's sendqueue (after fragmentation if
ashleymills 0:04990d454f45 1177 * necessary) and initialize retransmit timer */
ashleymills 0:04990d454f45 1178 res = CALL(ctx, write, &peer->session, sendbuf, len);
ashleymills 0:04990d454f45 1179
ashleymills 0:04990d454f45 1180 /* Guess number of bytes application data actually sent:
ashleymills 0:04990d454f45 1181 * dtls_prepare_record() tells us in len the number of bytes to
ashleymills 0:04990d454f45 1182 * send, res will contain the bytes actually sent. */
ashleymills 0:04990d454f45 1183 return res <= 0 ? res : buflen - (len - res);
ashleymills 0:04990d454f45 1184 }
ashleymills 0:04990d454f45 1185
ashleymills 0:04990d454f45 1186 static inline int
ashleymills 0:04990d454f45 1187 dtls_alert(dtls_context_t *ctx, dtls_peer_t *peer, dtls_alert_level_t level,
ashleymills 0:04990d454f45 1188 dtls_alert_t description) {
ashleymills 0:04990d454f45 1189 uint8_t msg[] = { level, description };
ashleymills 0:04990d454f45 1190
ashleymills 0:04990d454f45 1191 dtls_send(ctx, peer, DTLS_CT_ALERT, msg, sizeof(msg));
ashleymills 0:04990d454f45 1192 return 0;
ashleymills 0:04990d454f45 1193 }
ashleymills 0:04990d454f45 1194
ashleymills 0:04990d454f45 1195 int
ashleymills 0:04990d454f45 1196 dtls_close(dtls_context_t *ctx, const session_t *remote) {
ashleymills 0:04990d454f45 1197 int res = -1;
ashleymills 0:04990d454f45 1198 dtls_peer_t *peer;
ashleymills 0:04990d454f45 1199
ashleymills 0:04990d454f45 1200 peer = dtls_get_peer(ctx, remote);
ashleymills 0:04990d454f45 1201
ashleymills 0:04990d454f45 1202 if (peer) {
ashleymills 0:04990d454f45 1203 res = dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_CLOSE);
ashleymills 0:04990d454f45 1204 /* indicate tear down */
ashleymills 0:04990d454f45 1205 peer->state = DTLS_STATE_CLOSING;
ashleymills 0:04990d454f45 1206 }
ashleymills 0:04990d454f45 1207 return res;
ashleymills 0:04990d454f45 1208 }
ashleymills 0:04990d454f45 1209
ashleymills 0:04990d454f45 1210 int
ashleymills 0:04990d454f45 1211 dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) {
ashleymills 0:04990d454f45 1212
ashleymills 0:04990d454f45 1213 static uint8 buf[DTLS_MAX_BUF];
ashleymills 0:04990d454f45 1214 uint8 *p = buf, *q = ctx->sendbuf;
ashleymills 0:04990d454f45 1215 size_t qlen = sizeof(ctx->sendbuf);
ashleymills 0:04990d454f45 1216 int res;
ashleymills 0:04990d454f45 1217 const dtls_key_t *key;
ashleymills 0:04990d454f45 1218 dtls_tick_t now;
ashleymills 0:04990d454f45 1219
ashleymills 0:04990d454f45 1220 /* Ensure that the largest message to create fits in our source
ashleymills 0:04990d454f45 1221 * buffer. (The size of the destination buffer is checked by the
ashleymills 0:04990d454f45 1222 * encoding function, so we do not need to guess.) */
ashleymills 0:04990d454f45 1223 assert(sizeof(buf) >=
ashleymills 0:04990d454f45 1224 DTLS_RH_LENGTH + DTLS_HS_LENGTH + DTLS_SH_LENGTH + 20);
ashleymills 0:04990d454f45 1225
ashleymills 0:04990d454f45 1226 if (CALL(ctx, get_key, &peer->session, NULL, 0, &key) < 0) {
ashleymills 1:bc8a649bad13 1227 DBG("dtls_send_server_hello(): no key for session available");
ashleymills 0:04990d454f45 1228 return -1;
ashleymills 0:04990d454f45 1229 }
ashleymills 0:04990d454f45 1230
ashleymills 0:04990d454f45 1231 /* Handshake header */
ashleymills 0:04990d454f45 1232 p = dtls_set_handshake_header(DTLS_HT_SERVER_HELLO,
ashleymills 0:04990d454f45 1233 peer,
ashleymills 0:04990d454f45 1234 DTLS_SH_LENGTH,
ashleymills 0:04990d454f45 1235 0, DTLS_SH_LENGTH,
ashleymills 0:04990d454f45 1236 buf);
ashleymills 0:04990d454f45 1237
ashleymills 0:04990d454f45 1238 /* ServerHello */
ashleymills 0:04990d454f45 1239 dtls_int_to_uint16(p, DTLS_VERSION);
ashleymills 0:04990d454f45 1240 p += sizeof(uint16);
ashleymills 0:04990d454f45 1241
ashleymills 0:04990d454f45 1242 /* Set server random: First 4 bytes are the server's Unix timestamp,
ashleymills 0:04990d454f45 1243 * followed by 28 bytes of generate random data. */
ashleymills 0:04990d454f45 1244 dtls_ticks(&now);
ashleymills 0:04990d454f45 1245 dtls_int_to_uint32(p, now / CLOCK_SECOND);
ashleymills 0:04990d454f45 1246 prng(p + 4, 28);
ashleymills 0:04990d454f45 1247
ashleymills 0:04990d454f45 1248 if (!calculate_key_block(ctx, OTHER_CONFIG(peer), key,
ashleymills 0:04990d454f45 1249 OTHER_CONFIG(peer)->client_random, p))
ashleymills 0:04990d454f45 1250 return -1;
ashleymills 0:04990d454f45 1251
ashleymills 0:04990d454f45 1252 p += 32;
ashleymills 0:04990d454f45 1253
ashleymills 0:04990d454f45 1254 *p++ = 0; /* no session id */
ashleymills 0:04990d454f45 1255
ashleymills 0:04990d454f45 1256 if (OTHER_CONFIG(peer)->cipher != TLS_NULL_WITH_NULL_NULL) {
ashleymills 0:04990d454f45 1257 /* selected cipher suite */
ashleymills 0:04990d454f45 1258 dtls_int_to_uint16(p, OTHER_CONFIG(peer)->cipher);
ashleymills 0:04990d454f45 1259 p += sizeof(uint16);
ashleymills 0:04990d454f45 1260
ashleymills 0:04990d454f45 1261 /* selected compression method */
ashleymills 0:04990d454f45 1262 if (OTHER_CONFIG(peer)->compression >= 0)
ashleymills 0:04990d454f45 1263 *p++ = compression_methods[OTHER_CONFIG(peer)->compression];
ashleymills 0:04990d454f45 1264
ashleymills 0:04990d454f45 1265 /* FIXME: if key->psk.id != NULL we need the server key exchange */
ashleymills 0:04990d454f45 1266
ashleymills 0:04990d454f45 1267 /* update the finish hash
ashleymills 0:04990d454f45 1268 (FIXME: better put this in generic record_send function) */
ashleymills 0:04990d454f45 1269 update_hs_hash(peer, buf, p - buf);
ashleymills 0:04990d454f45 1270 }
ashleymills 0:04990d454f45 1271
ashleymills 0:04990d454f45 1272 res = dtls_prepare_record(peer, DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 1273 buf, p - buf,
ashleymills 0:04990d454f45 1274 q, &qlen);
ashleymills 0:04990d454f45 1275 if (res < 0) {
ashleymills 1:bc8a649bad13 1276 DBG("dtls_server_hello: cannot prepare ServerHello record");
ashleymills 0:04990d454f45 1277 return res;
ashleymills 0:04990d454f45 1278 }
ashleymills 0:04990d454f45 1279
ashleymills 0:04990d454f45 1280 q += qlen;
ashleymills 0:04990d454f45 1281 qlen = sizeof(ctx->sendbuf) - qlen;
ashleymills 0:04990d454f45 1282
ashleymills 0:04990d454f45 1283 /* ServerHelloDone
ashleymills 0:04990d454f45 1284 *
ashleymills 0:04990d454f45 1285 * Start message construction at beginning of buffer. */
ashleymills 0:04990d454f45 1286 p = dtls_set_handshake_header(DTLS_HT_SERVER_HELLO_DONE,
ashleymills 0:04990d454f45 1287 peer,
ashleymills 0:04990d454f45 1288 0, /* ServerHelloDone has no extra fields */
ashleymills 0:04990d454f45 1289 0, 0, /* ServerHelloDone has no extra fields */
ashleymills 0:04990d454f45 1290 buf);
ashleymills 0:04990d454f45 1291
ashleymills 0:04990d454f45 1292 /* update the finish hash
ashleymills 0:04990d454f45 1293 (FIXME: better put this in generic record_send function) */
ashleymills 0:04990d454f45 1294 update_hs_hash(peer, buf, p - buf);
ashleymills 0:04990d454f45 1295
ashleymills 0:04990d454f45 1296 res = dtls_prepare_record(peer, DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 1297 buf, p - buf,
ashleymills 0:04990d454f45 1298 q, &qlen);
ashleymills 0:04990d454f45 1299 if (res < 0) {
ashleymills 1:bc8a649bad13 1300 DBG("dtls_server_hello: cannot prepare ServerHelloDone record");
ashleymills 0:04990d454f45 1301 return res;
ashleymills 0:04990d454f45 1302 }
ashleymills 0:04990d454f45 1303
ashleymills 0:04990d454f45 1304 return CALL(ctx, write, &peer->session,
ashleymills 0:04990d454f45 1305 ctx->sendbuf, (q + qlen) - ctx->sendbuf);
ashleymills 0:04990d454f45 1306 }
ashleymills 0:04990d454f45 1307
ashleymills 0:04990d454f45 1308 static inline int
ashleymills 0:04990d454f45 1309 dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) {
ashleymills 0:04990d454f45 1310 ctx->sendbuf[0] = 1;
ashleymills 0:04990d454f45 1311 return dtls_send(ctx, peer, DTLS_CT_CHANGE_CIPHER_SPEC, ctx->sendbuf, 1);
ashleymills 0:04990d454f45 1312 }
ashleymills 0:04990d454f45 1313
ashleymills 0:04990d454f45 1314
ashleymills 0:04990d454f45 1315 int
ashleymills 0:04990d454f45 1316 dtls_send_kx(dtls_context_t *ctx, dtls_peer_t *peer, int is_client) {
ashleymills 0:04990d454f45 1317 const dtls_key_t *key;
ashleymills 0:04990d454f45 1318 uint8 *p = ctx->sendbuf;
ashleymills 0:04990d454f45 1319 size_t size;
ashleymills 0:04990d454f45 1320 int ht = is_client
ashleymills 0:04990d454f45 1321 ? DTLS_HT_CLIENT_KEY_EXCHANGE
ashleymills 0:04990d454f45 1322 : DTLS_HT_SERVER_KEY_EXCHANGE;
ashleymills 0:04990d454f45 1323 unsigned char *id = NULL;
ashleymills 0:04990d454f45 1324 size_t id_len = 0;
ashleymills 0:04990d454f45 1325
ashleymills 0:04990d454f45 1326 if (CALL(ctx, get_key, &peer->session, NULL, 0, &key) < 0) {
ashleymills 1:bc8a649bad13 1327 DBG("No key to send in kx. Fail.");
ashleymills 0:04990d454f45 1328 return -2;
ashleymills 0:04990d454f45 1329 }
ashleymills 0:04990d454f45 1330
ashleymills 0:04990d454f45 1331 assert(key);
ashleymills 0:04990d454f45 1332
ashleymills 0:04990d454f45 1333 switch (key->type) {
ashleymills 0:04990d454f45 1334 case DTLS_KEY_PSK: {
ashleymills 0:04990d454f45 1335 id_len = key->key.psk.id_length;
ashleymills 0:04990d454f45 1336 id = key->key.psk.id;
ashleymills 0:04990d454f45 1337 break;
ashleymills 0:04990d454f45 1338 }
ashleymills 0:04990d454f45 1339 default:
ashleymills 1:bc8a649bad13 1340 DBG("Key type not supported. Fail.");
ashleymills 0:04990d454f45 1341 return -3;
ashleymills 0:04990d454f45 1342 }
ashleymills 0:04990d454f45 1343
ashleymills 0:04990d454f45 1344 size = id_len + sizeof(uint16);
ashleymills 0:04990d454f45 1345 p = dtls_set_handshake_header(ht, peer, size, 0, size, p);
ashleymills 0:04990d454f45 1346
ashleymills 0:04990d454f45 1347 dtls_int_to_uint16(p, id_len);
ashleymills 0:04990d454f45 1348 memcpy(p + sizeof(uint16), id, id_len);
ashleymills 0:04990d454f45 1349
ashleymills 0:04990d454f45 1350 p += size;
ashleymills 0:04990d454f45 1351
ashleymills 0:04990d454f45 1352 update_hs_hash(peer, ctx->sendbuf, p - ctx->sendbuf);
ashleymills 0:04990d454f45 1353 return dtls_send(ctx, peer, DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 1354 ctx->sendbuf, p - ctx->sendbuf);
ashleymills 0:04990d454f45 1355 }
ashleymills 0:04990d454f45 1356
ashleymills 0:04990d454f45 1357 #define msg_overhead(Peer,Length) (DTLS_RH_LENGTH + \
ashleymills 0:04990d454f45 1358 ((Length + dtls_kb_iv_size(CURRENT_CONFIG(Peer)) + \
ashleymills 0:04990d454f45 1359 dtls_kb_digest_size(CURRENT_CONFIG(Peer))) / \
ashleymills 0:04990d454f45 1360 DTLS_BLK_LENGTH + 1) * DTLS_BLK_LENGTH)
ashleymills 0:04990d454f45 1361
ashleymills 0:04990d454f45 1362 int
ashleymills 0:04990d454f45 1363 dtls_send_server_finished(dtls_context_t *ctx, dtls_peer_t *peer) {
ashleymills 0:04990d454f45 1364
ashleymills 0:04990d454f45 1365 int length;
ashleymills 0:04990d454f45 1366 uint8 buf[DTLS_HMAC_MAX];
ashleymills 0:04990d454f45 1367 uint8 *p = ctx->sendbuf;
ashleymills 0:04990d454f45 1368
ashleymills 0:04990d454f45 1369 /* FIXME: adjust message overhead calculation */
ashleymills 0:04990d454f45 1370 assert(msg_overhead(peer, DTLS_HS_LENGTH + DTLS_FIN_LENGTH)
ashleymills 0:04990d454f45 1371 < sizeof(ctx->sendbuf));
ashleymills 0:04990d454f45 1372
ashleymills 0:04990d454f45 1373 p = dtls_set_handshake_header(DTLS_HT_FINISHED,
ashleymills 0:04990d454f45 1374 peer, DTLS_FIN_LENGTH, 0, DTLS_FIN_LENGTH, p);
ashleymills 0:04990d454f45 1375
ashleymills 0:04990d454f45 1376 length = finalize_hs_hash(peer, buf);
ashleymills 0:04990d454f45 1377
ashleymills 0:04990d454f45 1378 dtls_prf(CURRENT_CONFIG(peer)->master_secret,
ashleymills 0:04990d454f45 1379 DTLS_MASTER_SECRET_LENGTH,
ashleymills 0:04990d454f45 1380 PRF_LABEL(server), PRF_LABEL_SIZE(server),
ashleymills 0:04990d454f45 1381 PRF_LABEL(finished), PRF_LABEL_SIZE(finished),
ashleymills 0:04990d454f45 1382 buf, length,
ashleymills 0:04990d454f45 1383 p, DTLS_FIN_LENGTH);
ashleymills 0:04990d454f45 1384
ashleymills 0:04990d454f45 1385 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1386 /* printf("server finished MAC:\t"); */
ashleymills 0:04990d454f45 1387 /* dump(p, DTLS_FIN_LENGTH); */
ashleymills 0:04990d454f45 1388 /* printf("\n"); */
ashleymills 0:04990d454f45 1389 /* #endif */
ashleymills 0:04990d454f45 1390
ashleymills 0:04990d454f45 1391 p += DTLS_FIN_LENGTH;
ashleymills 0:04990d454f45 1392
ashleymills 0:04990d454f45 1393 return dtls_send(ctx, peer, DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 1394 ctx->sendbuf, p - ctx->sendbuf);
ashleymills 0:04990d454f45 1395 }
ashleymills 0:04990d454f45 1396
ashleymills 0:04990d454f45 1397 static int
ashleymills 0:04990d454f45 1398 check_server_hello(dtls_context_t *ctx,
ashleymills 0:04990d454f45 1399 dtls_peer_t *peer,
ashleymills 0:04990d454f45 1400 uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 1401 dtls_hello_verify_t *hv;
ashleymills 0:04990d454f45 1402 uint8 *p = ctx->sendbuf;
ashleymills 0:04990d454f45 1403 size_t size;
ashleymills 0:04990d454f45 1404 int res;
ashleymills 0:04990d454f45 1405 const dtls_key_t *key;
ashleymills 0:04990d454f45 1406
ashleymills 0:04990d454f45 1407 /* This function is called when we expect a ServerHello (i.e. we
ashleymills 0:04990d454f45 1408 * have sent a ClientHello). We might instead receive a HelloVerify
ashleymills 0:04990d454f45 1409 * request containing a cookie. If so, we must repeat the
ashleymills 0:04990d454f45 1410 * ClientHello with the given Cookie.
ashleymills 0:04990d454f45 1411 */
ashleymills 0:04990d454f45 1412
ashleymills 0:04990d454f45 1413 if (IS_SERVERHELLO(data, data_length)) {
ashleymills 1:bc8a649bad13 1414 DBG("handle ServerHello");
ashleymills 0:04990d454f45 1415
ashleymills 0:04990d454f45 1416 update_hs_hash(peer, data, data_length);
ashleymills 0:04990d454f45 1417
ashleymills 0:04990d454f45 1418 /* FIXME: check data_length before accessing fields */
ashleymills 0:04990d454f45 1419
ashleymills 0:04990d454f45 1420 /* Get the server's random data and store selected cipher suite
ashleymills 0:04990d454f45 1421 * and compression method (like dtls_update_parameters().
ashleymills 0:04990d454f45 1422 * Then calculate master secret and wait for ServerHelloDone. When received,
ashleymills 0:04990d454f45 1423 * send ClientKeyExchange (?) and ChangeCipherSpec + ClientFinished. */
ashleymills 0:04990d454f45 1424
ashleymills 0:04990d454f45 1425 /* check server version */
ashleymills 0:04990d454f45 1426 data += DTLS_HS_LENGTH;
ashleymills 0:04990d454f45 1427 data_length -= DTLS_HS_LENGTH;
ashleymills 0:04990d454f45 1428
ashleymills 0:04990d454f45 1429 if (dtls_uint16_to_int(data) != DTLS_VERSION) {
ashleymills 1:bc8a649bad13 1430 INFO("Unknown DTLS version");
ashleymills 0:04990d454f45 1431 goto error;
ashleymills 0:04990d454f45 1432 }
ashleymills 0:04990d454f45 1433
ashleymills 0:04990d454f45 1434 data += sizeof(uint16); /* skip version field */
ashleymills 0:04990d454f45 1435 data_length -= sizeof(uint16);
ashleymills 0:04990d454f45 1436
ashleymills 0:04990d454f45 1437 /* FIXME: check PSK hint */
ashleymills 0:04990d454f45 1438 if (CALL(ctx, get_key, &peer->session, NULL, 0, &key) < 0
ashleymills 0:04990d454f45 1439 || !calculate_key_block(ctx, OTHER_CONFIG(peer), key,
ashleymills 0:04990d454f45 1440 OTHER_CONFIG(peer)->client_random, data)) {
ashleymills 0:04990d454f45 1441 goto error;
ashleymills 0:04990d454f45 1442 }
ashleymills 0:04990d454f45 1443 /* store server random data */
ashleymills 0:04990d454f45 1444
ashleymills 0:04990d454f45 1445 /* memcpy(OTHER_CONFIG(peer)->server_random, data, */
ashleymills 0:04990d454f45 1446 /* sizeof(OTHER_CONFIG(peer)->server_random)); */
ashleymills 0:04990d454f45 1447 data += sizeof(OTHER_CONFIG(peer)->client_random);
ashleymills 0:04990d454f45 1448 data_length -= sizeof(OTHER_CONFIG(peer)->client_random);
ashleymills 0:04990d454f45 1449
ashleymills 0:04990d454f45 1450 SKIP_VAR_FIELD(data, data_length, uint8); /* skip session id */
ashleymills 0:04990d454f45 1451
ashleymills 0:04990d454f45 1452 /* Check cipher suite. As we offer all we have, it is sufficient
ashleymills 0:04990d454f45 1453 * to check if the cipher suite selected by the server is in our
ashleymills 0:04990d454f45 1454 * list of known cipher suites. Subsets are not supported. */
ashleymills 0:04990d454f45 1455 OTHER_CONFIG(peer)->cipher = dtls_uint16_to_int(data);
ashleymills 0:04990d454f45 1456 if (!known_cipher(OTHER_CONFIG(peer)->cipher)) {
ashleymills 1:bc8a649bad13 1457 INFO("Unsupported cipher 0x%02x 0x%02x\n",data[0], data[1]);
ashleymills 0:04990d454f45 1458 goto error;
ashleymills 0:04990d454f45 1459 }
ashleymills 0:04990d454f45 1460 data += sizeof(uint16);
ashleymills 0:04990d454f45 1461 data_length -= sizeof(uint16);
ashleymills 0:04990d454f45 1462
ashleymills 0:04990d454f45 1463 /* Check if NULL compression was selected. We do not know any other. */
ashleymills 0:04990d454f45 1464 if (dtls_uint8_to_int(data) != TLS_COMP_NULL) {
ashleymills 1:bc8a649bad13 1465 INFO("Unsupported compression method 0x%02x\n", data[0]);
ashleymills 0:04990d454f45 1466 goto error;
ashleymills 0:04990d454f45 1467 }
ashleymills 0:04990d454f45 1468
ashleymills 0:04990d454f45 1469 return 1;
ashleymills 0:04990d454f45 1470 }
ashleymills 0:04990d454f45 1471
ashleymills 0:04990d454f45 1472 if (!IS_HELLOVERIFY(data, data_length)) {
ashleymills 1:bc8a649bad13 1473 DBG("No HelloVerify");
ashleymills 0:04990d454f45 1474 return 0;
ashleymills 0:04990d454f45 1475 }
ashleymills 0:04990d454f45 1476
ashleymills 1:bc8a649bad13 1477 DBG("Got HelloVerify");
ashleymills 0:04990d454f45 1478 hv = (dtls_hello_verify_t *)(data + DTLS_HS_LENGTH);
ashleymills 0:04990d454f45 1479
ashleymills 0:04990d454f45 1480 /* FIXME: dtls_send_client_hello(ctx,peer,cookie) */
ashleymills 0:04990d454f45 1481 size = DTLS_CH_LENGTH + 8 + dtls_uint8_to_int(&hv->cookie_length);
ashleymills 0:04990d454f45 1482
ashleymills 0:04990d454f45 1483 p = dtls_set_handshake_header(DTLS_HT_CLIENT_HELLO, peer,
ashleymills 0:04990d454f45 1484 size, 0, size, p);
ashleymills 0:04990d454f45 1485
ashleymills 0:04990d454f45 1486 dtls_int_to_uint16(p, DTLS_VERSION);
ashleymills 0:04990d454f45 1487 p += sizeof(uint16);
ashleymills 0:04990d454f45 1488
ashleymills 0:04990d454f45 1489 /* we must use the same Client Random as for the previous request */
ashleymills 0:04990d454f45 1490 memcpy(p, OTHER_CONFIG(peer)->client_random,
ashleymills 0:04990d454f45 1491 sizeof(OTHER_CONFIG(peer)->client_random));
ashleymills 0:04990d454f45 1492 p += sizeof(OTHER_CONFIG(peer)->client_random);
ashleymills 0:04990d454f45 1493
ashleymills 0:04990d454f45 1494 /* session id (length 0) */
ashleymills 0:04990d454f45 1495 dtls_int_to_uint8(p, 0);
ashleymills 0:04990d454f45 1496 p += sizeof(uint8);
ashleymills 0:04990d454f45 1497
ashleymills 0:04990d454f45 1498 dtls_int_to_uint8(p, dtls_uint8_to_int(&hv->cookie_length));
ashleymills 0:04990d454f45 1499 p += sizeof(uint8);
ashleymills 0:04990d454f45 1500 memcpy(p, hv->cookie, dtls_uint8_to_int(&hv->cookie_length));
ashleymills 0:04990d454f45 1501 p += dtls_uint8_to_int(&hv->cookie_length);
ashleymills 0:04990d454f45 1502
ashleymills 0:04990d454f45 1503 /* add known cipher(s) */
ashleymills 0:04990d454f45 1504 dtls_int_to_uint16(p, 2);
ashleymills 0:04990d454f45 1505 p += sizeof(uint16);
ashleymills 0:04990d454f45 1506
ashleymills 0:04990d454f45 1507 dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8);
ashleymills 0:04990d454f45 1508 p += sizeof(uint16);
ashleymills 0:04990d454f45 1509
ashleymills 0:04990d454f45 1510 /* compression method */
ashleymills 0:04990d454f45 1511 dtls_int_to_uint8(p, 1);
ashleymills 0:04990d454f45 1512 p += sizeof(uint8);
ashleymills 0:04990d454f45 1513
ashleymills 0:04990d454f45 1514 dtls_int_to_uint8(p, 0);
ashleymills 0:04990d454f45 1515 p += sizeof(uint8);
ashleymills 0:04990d454f45 1516
ashleymills 0:04990d454f45 1517 update_hs_hash(peer, ctx->sendbuf, p - ctx->sendbuf);
ashleymills 0:04990d454f45 1518
ashleymills 0:04990d454f45 1519 res = dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, ctx->sendbuf,
ashleymills 0:04990d454f45 1520 p - ctx->sendbuf);
ashleymills 0:04990d454f45 1521 if (res < 0)
ashleymills 1:bc8a649bad13 1522 WARN("cannot send ClientHello");
ashleymills 0:04990d454f45 1523
ashleymills 0:04990d454f45 1524 error:
ashleymills 0:04990d454f45 1525 return 0;
ashleymills 0:04990d454f45 1526 }
ashleymills 0:04990d454f45 1527
ashleymills 0:04990d454f45 1528 static int
ashleymills 0:04990d454f45 1529 check_server_hellodone(dtls_context_t *ctx,
ashleymills 0:04990d454f45 1530 dtls_peer_t *peer,
ashleymills 0:04990d454f45 1531 uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 1532
ashleymills 0:04990d454f45 1533 /* calculate master key, send CCS */
ashleymills 0:04990d454f45 1534 if (!IS_SERVERHELLODONE(data, data_length))
ashleymills 0:04990d454f45 1535 return 0;
ashleymills 0:04990d454f45 1536
ashleymills 0:04990d454f45 1537 update_hs_hash(peer, data, data_length);
ashleymills 0:04990d454f45 1538
ashleymills 0:04990d454f45 1539 /* set crypto context for TLS_PSK_WITH_AES_128_CCM_8 */
ashleymills 0:04990d454f45 1540 /* client */
ashleymills 0:04990d454f45 1541 dtls_cipher_free(OTHER_CONFIG(peer)->read_cipher);
ashleymills 0:04990d454f45 1542
ashleymills 0:04990d454f45 1543 assert(OTHER_CONFIG(peer)->cipher != TLS_NULL_WITH_NULL_NULL);
ashleymills 0:04990d454f45 1544 OTHER_CONFIG(peer)->read_cipher =
ashleymills 0:04990d454f45 1545 dtls_cipher_new(OTHER_CONFIG(peer)->cipher,
ashleymills 0:04990d454f45 1546 dtls_kb_server_write_key(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 1547 dtls_kb_key_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 1548
ashleymills 0:04990d454f45 1549 if (!OTHER_CONFIG(peer)->read_cipher) {
ashleymills 1:bc8a649bad13 1550 WARN("Cannot create read cipher");
ashleymills 0:04990d454f45 1551 return 0;
ashleymills 0:04990d454f45 1552 }
ashleymills 0:04990d454f45 1553
ashleymills 0:04990d454f45 1554 dtls_cipher_set_iv(OTHER_CONFIG(peer)->read_cipher,
ashleymills 0:04990d454f45 1555 dtls_kb_server_iv(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 1556 dtls_kb_iv_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 1557
ashleymills 0:04990d454f45 1558 /* server */
ashleymills 0:04990d454f45 1559 dtls_cipher_free(OTHER_CONFIG(peer)->write_cipher);
ashleymills 0:04990d454f45 1560
ashleymills 0:04990d454f45 1561 OTHER_CONFIG(peer)->write_cipher =
ashleymills 0:04990d454f45 1562 dtls_cipher_new(OTHER_CONFIG(peer)->cipher,
ashleymills 0:04990d454f45 1563 dtls_kb_client_write_key(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 1564 dtls_kb_key_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 1565
ashleymills 0:04990d454f45 1566 if (!OTHER_CONFIG(peer)->write_cipher) {
ashleymills 0:04990d454f45 1567 dtls_cipher_free(OTHER_CONFIG(peer)->read_cipher);
ashleymills 1:bc8a649bad13 1568 WARN("Cannot create write cipher");
ashleymills 0:04990d454f45 1569 return 0;
ashleymills 0:04990d454f45 1570 }
ashleymills 0:04990d454f45 1571
ashleymills 0:04990d454f45 1572 dtls_cipher_set_iv(OTHER_CONFIG(peer)->write_cipher,
ashleymills 0:04990d454f45 1573 dtls_kb_client_iv(OTHER_CONFIG(peer)),
ashleymills 0:04990d454f45 1574 dtls_kb_iv_size(OTHER_CONFIG(peer)));
ashleymills 0:04990d454f45 1575
ashleymills 0:04990d454f45 1576 /* send ClientKeyExchange */
ashleymills 0:04990d454f45 1577 if (dtls_send_kx(ctx, peer, 1) < 0) {
ashleymills 1:bc8a649bad13 1578 DBG("Cannot send KeyExchange message");
ashleymills 0:04990d454f45 1579 return 0;
ashleymills 0:04990d454f45 1580 }
ashleymills 0:04990d454f45 1581
ashleymills 0:04990d454f45 1582 /* and switch cipher suite */
ashleymills 0:04990d454f45 1583 if (dtls_send_ccs(ctx, peer) < 0) {
ashleymills 1:bc8a649bad13 1584 DBG("Cannot send CCS message");
ashleymills 0:04990d454f45 1585 return 0;
ashleymills 0:04990d454f45 1586 }
ashleymills 0:04990d454f45 1587
ashleymills 0:04990d454f45 1588 SWITCH_CONFIG(peer);
ashleymills 0:04990d454f45 1589 inc_uint(uint16, peer->epoch);
ashleymills 0:04990d454f45 1590 memset(peer->rseq, 0, sizeof(peer->rseq));
ashleymills 0:04990d454f45 1591 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1592 /* { */
ashleymills 0:04990d454f45 1593 /* printf("key_block:\n"); */
ashleymills 0:04990d454f45 1594 /* printf(" client_MAC_secret:\t"); */
ashleymills 0:04990d454f45 1595 /* dump(dtls_kb_client_mac_secret(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1596 /* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1597 /* printf("\n"); */
ashleymills 0:04990d454f45 1598
ashleymills 0:04990d454f45 1599 /* printf(" server_MAC_secret:\t"); */
ashleymills 0:04990d454f45 1600 /* dump(dtls_kb_server_mac_secret(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1601 /* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1602 /* printf("\n"); */
ashleymills 0:04990d454f45 1603
ashleymills 0:04990d454f45 1604 /* printf(" client_write_key:\t"); */
ashleymills 0:04990d454f45 1605 /* dump(dtls_kb_client_write_key(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1606 /* dtls_kb_key_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1607 /* printf("\n"); */
ashleymills 0:04990d454f45 1608
ashleymills 0:04990d454f45 1609 /* printf(" server_write_key:\t"); */
ashleymills 0:04990d454f45 1610 /* dump(dtls_kb_server_write_key(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1611 /* dtls_kb_key_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1612 /* printf("\n"); */
ashleymills 0:04990d454f45 1613
ashleymills 0:04990d454f45 1614 /* printf(" client_IV:\t\t"); */
ashleymills 0:04990d454f45 1615 /* dump(dtls_kb_client_iv(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1616 /* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1617 /* printf("\n"); */
ashleymills 0:04990d454f45 1618
ashleymills 0:04990d454f45 1619 /* printf(" server_IV:\t\t"); */
ashleymills 0:04990d454f45 1620 /* dump(dtls_kb_server_iv(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1621 /* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1622 /* printf("\n"); */
ashleymills 0:04990d454f45 1623
ashleymills 0:04990d454f45 1624
ashleymills 0:04990d454f45 1625 /* } */
ashleymills 0:04990d454f45 1626 /* #endif */
ashleymills 0:04990d454f45 1627
ashleymills 0:04990d454f45 1628 /* Client Finished */
ashleymills 0:04990d454f45 1629 {
ashleymills 1:bc8a649bad13 1630 DBG("Send Finished");
ashleymills 0:04990d454f45 1631 int length;
ashleymills 0:04990d454f45 1632 uint8 buf[DTLS_HMAC_MAX];
ashleymills 0:04990d454f45 1633 uint8 *p = ctx->sendbuf;
ashleymills 0:04990d454f45 1634
ashleymills 0:04990d454f45 1635 unsigned char statebuf[DTLS_HASH_CTX_SIZE];
ashleymills 0:04990d454f45 1636
ashleymills 0:04990d454f45 1637 /* FIXME: adjust message overhead calculation */
ashleymills 0:04990d454f45 1638 assert(msg_overhead(peer, DTLS_HS_LENGTH + DTLS_FIN_LENGTH)
ashleymills 0:04990d454f45 1639 < sizeof(ctx->sendbuf));
ashleymills 0:04990d454f45 1640
ashleymills 0:04990d454f45 1641 p = dtls_set_handshake_header(DTLS_HT_FINISHED,
ashleymills 0:04990d454f45 1642 peer, DTLS_FIN_LENGTH,
ashleymills 0:04990d454f45 1643 0, DTLS_FIN_LENGTH, p);
ashleymills 0:04990d454f45 1644
ashleymills 0:04990d454f45 1645 /* temporarily store hash status for roll-back after finalize */
ashleymills 0:04990d454f45 1646 memcpy(statebuf, &peer->hs_state.hs_hash, DTLS_HASH_CTX_SIZE);
ashleymills 0:04990d454f45 1647
ashleymills 0:04990d454f45 1648 length = finalize_hs_hash(peer, buf);
ashleymills 0:04990d454f45 1649
ashleymills 0:04990d454f45 1650 /* restore hash status */
ashleymills 0:04990d454f45 1651 memcpy(&peer->hs_state.hs_hash, statebuf, DTLS_HASH_CTX_SIZE);
ashleymills 0:04990d454f45 1652
ashleymills 0:04990d454f45 1653 dtls_prf(CURRENT_CONFIG(peer)->master_secret,
ashleymills 0:04990d454f45 1654 DTLS_MASTER_SECRET_LENGTH,
ashleymills 0:04990d454f45 1655 PRF_LABEL(client), PRF_LABEL_SIZE(client),
ashleymills 0:04990d454f45 1656 PRF_LABEL(finished), PRF_LABEL_SIZE(finished),
ashleymills 0:04990d454f45 1657 buf, length,
ashleymills 0:04990d454f45 1658 p, DTLS_FIN_LENGTH);
ashleymills 0:04990d454f45 1659
ashleymills 0:04990d454f45 1660 p += DTLS_FIN_LENGTH;
ashleymills 0:04990d454f45 1661
ashleymills 0:04990d454f45 1662 update_hs_hash(peer, ctx->sendbuf, p - ctx->sendbuf);
ashleymills 0:04990d454f45 1663 if (dtls_send(ctx, peer, DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 1664 ctx->sendbuf, p - ctx->sendbuf) < 0) {
ashleymills 1:bc8a649bad13 1665 INFO("Cannot send Finished message");
ashleymills 0:04990d454f45 1666 return 0;
ashleymills 0:04990d454f45 1667 }
ashleymills 0:04990d454f45 1668 }
ashleymills 0:04990d454f45 1669 return 1;
ashleymills 0:04990d454f45 1670 }
ashleymills 0:04990d454f45 1671
ashleymills 0:04990d454f45 1672 int
ashleymills 0:04990d454f45 1673 decrypt_verify(dtls_peer_t *peer,
ashleymills 0:04990d454f45 1674 uint8 *packet, size_t length,
ashleymills 0:04990d454f45 1675 uint8 **cleartext, size_t *clen) {
ashleymills 0:04990d454f45 1676 int ok = 0;
ashleymills 0:04990d454f45 1677
ashleymills 0:04990d454f45 1678 *cleartext = (uint8 *)packet + sizeof(dtls_record_header_t);
ashleymills 0:04990d454f45 1679 *clen = length - sizeof(dtls_record_header_t);
ashleymills 0:04990d454f45 1680
ashleymills 0:04990d454f45 1681 if (CURRENT_CONFIG(peer)->cipher == TLS_NULL_WITH_NULL_NULL) {
ashleymills 0:04990d454f45 1682 /* no cipher suite selected */
ashleymills 0:04990d454f45 1683 return 1;
ashleymills 0:04990d454f45 1684 } else { /* TLS_PSK_WITH_AES_128_CCM_8 */
ashleymills 0:04990d454f45 1685 dtls_cipher_context_t *cipher_context;
ashleymills 0:04990d454f45 1686 /**
ashleymills 0:04990d454f45 1687 * length of additional_data for the AEAD cipher which consists of
ashleymills 0:04990d454f45 1688 * seq_num(2+6) + type(1) + version(2) + length(2)
ashleymills 0:04990d454f45 1689 */
ashleymills 0:04990d454f45 1690 #define A_DATA_LEN 13
ashleymills 0:04990d454f45 1691 #define A_DATA N
ashleymills 0:04990d454f45 1692 unsigned char N[max(DTLS_CCM_BLOCKSIZE, A_DATA_LEN)];
ashleymills 0:04990d454f45 1693 long int len;
ashleymills 0:04990d454f45 1694
ashleymills 0:04990d454f45 1695
ashleymills 0:04990d454f45 1696 if (*clen < 16) /* need at least IV and MAC */
ashleymills 0:04990d454f45 1697 return -1;
ashleymills 0:04990d454f45 1698
ashleymills 0:04990d454f45 1699 memset(N, 0, DTLS_CCM_BLOCKSIZE);
ashleymills 0:04990d454f45 1700 memcpy(N, dtls_kb_remote_iv(CURRENT_CONFIG(peer)),
ashleymills 0:04990d454f45 1701 dtls_kb_iv_size(CURRENT_CONFIG(peer)));
ashleymills 0:04990d454f45 1702
ashleymills 0:04990d454f45 1703 /* read epoch and seq_num from message */
ashleymills 0:04990d454f45 1704 memcpy(N + dtls_kb_iv_size(CURRENT_CONFIG(peer)), *cleartext, 8);
ashleymills 0:04990d454f45 1705 *cleartext += 8;
ashleymills 0:04990d454f45 1706 *clen -= 8;
ashleymills 0:04990d454f45 1707
ashleymills 0:04990d454f45 1708 cipher_context = CURRENT_CONFIG(peer)->read_cipher;
ashleymills 0:04990d454f45 1709
ashleymills 0:04990d454f45 1710 if (!cipher_context) {
ashleymills 1:bc8a649bad13 1711 WARN("No read_cipher available!");
ashleymills 0:04990d454f45 1712 return 0;
ashleymills 0:04990d454f45 1713 }
ashleymills 0:04990d454f45 1714
ashleymills 0:04990d454f45 1715 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1716 /* printf("nonce:\t"); */
ashleymills 0:04990d454f45 1717 /* dump(N, DTLS_CCM_BLOCKSIZE); */
ashleymills 0:04990d454f45 1718 /* printf("\nkey:\t"); */
ashleymills 0:04990d454f45 1719 /* dump(dtls_kb_remote_write_key(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1720 /* dtls_kb_key_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1721 /* printf("\nciphertext:\n"); */
ashleymills 0:04990d454f45 1722 /* dump(*cleartext, *clen); */
ashleymills 0:04990d454f45 1723 /* printf("\n"); */
ashleymills 0:04990d454f45 1724 /* #endif */
ashleymills 0:04990d454f45 1725
ashleymills 0:04990d454f45 1726 dtls_cipher_set_iv(cipher_context, N, DTLS_CCM_BLOCKSIZE);
ashleymills 0:04990d454f45 1727
ashleymills 0:04990d454f45 1728 /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3:
ashleymills 0:04990d454f45 1729 *
ashleymills 0:04990d454f45 1730 * additional_data = seq_num + TLSCompressed.type +
ashleymills 0:04990d454f45 1731 * TLSCompressed.version + TLSCompressed.length;
ashleymills 0:04990d454f45 1732 */
ashleymills 0:04990d454f45 1733 memcpy(A_DATA, &DTLS_RECORD_HEADER(packet)->epoch, 8); /* epoch and seq_num */
ashleymills 0:04990d454f45 1734 memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(packet)->content_type, 3); /* type and version */
ashleymills 0:04990d454f45 1735 dtls_int_to_uint16(A_DATA + 11, *clen - 8); /* length without nonce_explicit */
ashleymills 0:04990d454f45 1736
ashleymills 0:04990d454f45 1737 len = dtls_decrypt(cipher_context, *cleartext, *clen, *cleartext,
ashleymills 0:04990d454f45 1738 A_DATA, A_DATA_LEN);
ashleymills 0:04990d454f45 1739
ashleymills 0:04990d454f45 1740 ok = len >= 0;
ashleymills 0:04990d454f45 1741 if (!ok)
ashleymills 1:bc8a649bad13 1742 WARN("decryption failed");
ashleymills 0:04990d454f45 1743 else {
ashleymills 0:04990d454f45 1744 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1745 /* printf("decrypt_verify(): found %ld bytes cleartext\n", len); */
ashleymills 0:04990d454f45 1746 /* #endif */
ashleymills 0:04990d454f45 1747 *clen = len;
ashleymills 0:04990d454f45 1748 }
ashleymills 0:04990d454f45 1749 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1750 /* printf("\ncleartext:\n"); */
ashleymills 0:04990d454f45 1751 /* dump(*cleartext, *clen); */
ashleymills 0:04990d454f45 1752 /* printf("\n"); */
ashleymills 0:04990d454f45 1753 /* #endif */
ashleymills 0:04990d454f45 1754 }
ashleymills 0:04990d454f45 1755
ashleymills 0:04990d454f45 1756 return ok;
ashleymills 0:04990d454f45 1757 }
ashleymills 0:04990d454f45 1758
ashleymills 0:04990d454f45 1759
ashleymills 0:04990d454f45 1760 int
ashleymills 0:04990d454f45 1761 handle_handshake(dtls_context_t *ctx, dtls_peer_t *peer,
ashleymills 0:04990d454f45 1762 uint8 *record_header, uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 1763
ashleymills 0:04990d454f45 1764 /* The following switch construct handles the given message with
ashleymills 0:04990d454f45 1765 * respect to the current internal state for this peer. In case of
ashleymills 0:04990d454f45 1766 * error, it is left with return 0. */
ashleymills 0:04990d454f45 1767
ashleymills 0:04990d454f45 1768 switch (peer->state) {
ashleymills 0:04990d454f45 1769
ashleymills 0:04990d454f45 1770 /************************************************************************
ashleymills 0:04990d454f45 1771 * Client states
ashleymills 0:04990d454f45 1772 ************************************************************************/
ashleymills 0:04990d454f45 1773
ashleymills 0:04990d454f45 1774 case DTLS_STATE_CLIENTHELLO:
ashleymills 0:04990d454f45 1775 /* here we expect a HelloVerify or ServerHello */
ashleymills 0:04990d454f45 1776
ashleymills 1:bc8a649bad13 1777 DBG("DTLS_STATE_CLIENTHELLO");
ashleymills 0:04990d454f45 1778 if (check_server_hello(ctx, peer, data, data_length)) {
ashleymills 0:04990d454f45 1779 peer->state = DTLS_STATE_WAIT_SERVERHELLODONE;
ashleymills 0:04990d454f45 1780 /* update_hs_hash(peer, data, data_length); */
ashleymills 0:04990d454f45 1781 }
ashleymills 0:04990d454f45 1782
ashleymills 0:04990d454f45 1783 break;
ashleymills 0:04990d454f45 1784
ashleymills 0:04990d454f45 1785 case DTLS_STATE_WAIT_SERVERHELLODONE:
ashleymills 0:04990d454f45 1786 /* expect a ServerHelloDone */
ashleymills 0:04990d454f45 1787
ashleymills 1:bc8a649bad13 1788 DBG("DTLS_STATE_WAIT_SERVERHELLODONE");
ashleymills 0:04990d454f45 1789
ashleymills 0:04990d454f45 1790 if (check_server_hellodone(ctx, peer, data, data_length)) {
ashleymills 0:04990d454f45 1791 peer->state = DTLS_STATE_WAIT_SERVERFINISHED;
ashleymills 0:04990d454f45 1792 /* update_hs_hash(peer, data, data_length); */
ashleymills 0:04990d454f45 1793 }
ashleymills 0:04990d454f45 1794
ashleymills 0:04990d454f45 1795 break;
ashleymills 0:04990d454f45 1796
ashleymills 0:04990d454f45 1797 case DTLS_STATE_WAIT_SERVERFINISHED:
ashleymills 0:04990d454f45 1798 /* expect a Finished message from server */
ashleymills 0:04990d454f45 1799
ashleymills 1:bc8a649bad13 1800 DBG("DTLS_STATE_WAIT_SERVERFINISHED");
ashleymills 0:04990d454f45 1801 if (check_finished(ctx, peer, record_header, data, data_length)) {
ashleymills 1:bc8a649bad13 1802 DBG("finished!");
ashleymills 0:04990d454f45 1803 peer->state = DTLS_STATE_CONNECTED;
ashleymills 0:04990d454f45 1804 }
ashleymills 0:04990d454f45 1805
ashleymills 0:04990d454f45 1806 break;
ashleymills 0:04990d454f45 1807
ashleymills 0:04990d454f45 1808 /************************************************************************
ashleymills 0:04990d454f45 1809 * Server states
ashleymills 0:04990d454f45 1810 ************************************************************************/
ashleymills 0:04990d454f45 1811
ashleymills 0:04990d454f45 1812 case DTLS_STATE_SERVERHELLO:
ashleymills 0:04990d454f45 1813 /* here we expect a ClientHello */
ashleymills 0:04990d454f45 1814 /* handle ClientHello, update msg and msglen and goto next if not finished */
ashleymills 0:04990d454f45 1815
ashleymills 1:bc8a649bad13 1816 DBG("DTLS_STATE_SERVERHELLO");
ashleymills 0:04990d454f45 1817 if (!check_client_keyexchange(ctx, peer, data, data_length)) {
ashleymills 1:bc8a649bad13 1818 WARN("check_client_keyexchange failed (%d, %d)", data_length, data[0]);
ashleymills 0:04990d454f45 1819 return 0; /* drop it, whatever it is */
ashleymills 0:04990d454f45 1820 }
ashleymills 0:04990d454f45 1821
ashleymills 0:04990d454f45 1822 update_hs_hash(peer, data, data_length);
ashleymills 0:04990d454f45 1823 peer->state = DTLS_STATE_KEYEXCHANGE;
ashleymills 0:04990d454f45 1824 break;
ashleymills 0:04990d454f45 1825
ashleymills 0:04990d454f45 1826 case DTLS_STATE_WAIT_FINISHED:
ashleymills 1:bc8a649bad13 1827 DBG("DTLS_STATE_WAIT_FINISHED");
ashleymills 0:04990d454f45 1828 if (check_finished(ctx, peer, record_header, data, data_length)) {
ashleymills 1:bc8a649bad13 1829 DBG("finished!");
ashleymills 0:04990d454f45 1830
ashleymills 0:04990d454f45 1831 /* send ServerFinished */
ashleymills 0:04990d454f45 1832 update_hs_hash(peer, data, data_length);
ashleymills 0:04990d454f45 1833
ashleymills 0:04990d454f45 1834 if (dtls_send_server_finished(ctx, peer) > 0) {
ashleymills 0:04990d454f45 1835 peer->state = DTLS_STATE_CONNECTED;
ashleymills 0:04990d454f45 1836 } else {
ashleymills 1:bc8a649bad13 1837 WARN("sending server Finished failed");
ashleymills 0:04990d454f45 1838 }
ashleymills 0:04990d454f45 1839 } else {
ashleymills 0:04990d454f45 1840 /* send alert */
ashleymills 0:04990d454f45 1841 }
ashleymills 0:04990d454f45 1842 break;
ashleymills 0:04990d454f45 1843
ashleymills 0:04990d454f45 1844 case DTLS_STATE_CONNECTED:
ashleymills 0:04990d454f45 1845 /* At this point, we have a good relationship with this peer. This
ashleymills 0:04990d454f45 1846 * state is left for re-negotiation of key material. */
ashleymills 0:04990d454f45 1847
ashleymills 1:bc8a649bad13 1848 DBG("DTLS_STATE_CONNECTED");
ashleymills 0:04990d454f45 1849
ashleymills 0:04990d454f45 1850 /* renegotiation */
ashleymills 0:04990d454f45 1851 if (dtls_verify_peer(ctx, peer, &peer->session,
ashleymills 0:04990d454f45 1852 record_header, data, data_length) > 0) {
ashleymills 0:04990d454f45 1853
ashleymills 0:04990d454f45 1854 clear_hs_hash(peer);
ashleymills 0:04990d454f45 1855
ashleymills 0:04990d454f45 1856 if (!dtls_update_parameters(ctx, peer, data, data_length)) {
ashleymills 0:04990d454f45 1857
ashleymills 1:bc8a649bad13 1858 WARN("Error updating security parameters");
ashleymills 0:04990d454f45 1859 dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_WARNING,
ashleymills 0:04990d454f45 1860 DTLS_ALERT_NO_RENEGOTIATION);
ashleymills 0:04990d454f45 1861 return 0;
ashleymills 0:04990d454f45 1862 }
ashleymills 0:04990d454f45 1863
ashleymills 0:04990d454f45 1864 /* update finish MAC */
ashleymills 0:04990d454f45 1865 update_hs_hash(peer, data, data_length);
ashleymills 0:04990d454f45 1866
ashleymills 0:04990d454f45 1867 if (dtls_send_server_hello(ctx, peer) > 0)
ashleymills 0:04990d454f45 1868 peer->state = DTLS_STATE_SERVERHELLO;
ashleymills 0:04990d454f45 1869
ashleymills 0:04990d454f45 1870 /* after sending the ServerHelloDone, we expect the
ashleymills 0:04990d454f45 1871 * ClientKeyExchange (possibly containing the PSK id),
ashleymills 0:04990d454f45 1872 * followed by a ChangeCipherSpec and an encrypted Finished.
ashleymills 0:04990d454f45 1873 */
ashleymills 0:04990d454f45 1874 }
ashleymills 0:04990d454f45 1875
ashleymills 0:04990d454f45 1876 break;
ashleymills 0:04990d454f45 1877
ashleymills 0:04990d454f45 1878 case DTLS_STATE_INIT: /* these states should not occur here */
ashleymills 0:04990d454f45 1879 case DTLS_STATE_KEYEXCHANGE:
ashleymills 0:04990d454f45 1880 default:
ashleymills 1:bc8a649bad13 1881 INFO("Unhandled state %d", peer->state);
ashleymills 0:04990d454f45 1882 assert(0);
ashleymills 0:04990d454f45 1883 }
ashleymills 0:04990d454f45 1884
ashleymills 0:04990d454f45 1885 return 1;
ashleymills 0:04990d454f45 1886 }
ashleymills 0:04990d454f45 1887
ashleymills 0:04990d454f45 1888 int
ashleymills 0:04990d454f45 1889 handle_ccs(dtls_context_t *ctx, dtls_peer_t *peer,
ashleymills 0:04990d454f45 1890 uint8 *record_header, uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 1891
ashleymills 0:04990d454f45 1892 /* A CCS message is handled after a KeyExchange message was
ashleymills 0:04990d454f45 1893 * received from the client. When security parameters have been
ashleymills 0:04990d454f45 1894 * updated successfully and a ChangeCipherSpec message was sent
ashleymills 0:04990d454f45 1895 * by ourself, the security context is switched and the record
ashleymills 0:04990d454f45 1896 * sequence number is reset. */
ashleymills 0:04990d454f45 1897
ashleymills 0:04990d454f45 1898 if (peer->state != DTLS_STATE_KEYEXCHANGE
ashleymills 0:04990d454f45 1899 || !check_ccs(ctx, peer, record_header, data, data_length)) {
ashleymills 0:04990d454f45 1900 /* signal error? */
ashleymills 1:bc8a649bad13 1901 WARN("Expected ChangeCipherSpec during handshake");
ashleymills 0:04990d454f45 1902 return 0;
ashleymills 0:04990d454f45 1903
ashleymills 0:04990d454f45 1904 }
ashleymills 0:04990d454f45 1905
ashleymills 0:04990d454f45 1906 /* send change cipher spec message and switch to new configuration */
ashleymills 0:04990d454f45 1907 if (dtls_send_ccs(ctx, peer) < 0) {
ashleymills 1:bc8a649bad13 1908 WARN("Cannot send CCS message");
ashleymills 0:04990d454f45 1909 return 0;
ashleymills 0:04990d454f45 1910 }
ashleymills 0:04990d454f45 1911
ashleymills 0:04990d454f45 1912 SWITCH_CONFIG(peer);
ashleymills 0:04990d454f45 1913 inc_uint(uint16, peer->epoch);
ashleymills 0:04990d454f45 1914 memset(peer->rseq, 0, sizeof(peer->rseq));
ashleymills 0:04990d454f45 1915
ashleymills 0:04990d454f45 1916 peer->state = DTLS_STATE_WAIT_FINISHED;
ashleymills 0:04990d454f45 1917
ashleymills 0:04990d454f45 1918 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1919 /* { */
ashleymills 0:04990d454f45 1920 /* printf("key_block:\n"); */
ashleymills 0:04990d454f45 1921 /* printf(" client_MAC_secret:\t"); */
ashleymills 0:04990d454f45 1922 /* dump(dtls_kb_client_mac_secret(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1923 /* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1924 /* printf("\n"); */
ashleymills 0:04990d454f45 1925
ashleymills 0:04990d454f45 1926 /* printf(" server_MAC_secret:\t"); */
ashleymills 0:04990d454f45 1927 /* dump(dtls_kb_server_mac_secret(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1928 /* dtls_kb_mac_secret_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1929 /* printf("\n"); */
ashleymills 0:04990d454f45 1930
ashleymills 0:04990d454f45 1931 /* printf(" client_write_key:\t"); */
ashleymills 0:04990d454f45 1932 /* dump(dtls_kb_client_write_key(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1933 /* dtls_kb_key_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1934 /* printf("\n"); */
ashleymills 0:04990d454f45 1935
ashleymills 0:04990d454f45 1936 /* printf(" server_write_key:\t"); */
ashleymills 0:04990d454f45 1937 /* dump(dtls_kb_server_write_key(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1938 /* dtls_kb_key_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1939 /* printf("\n"); */
ashleymills 0:04990d454f45 1940
ashleymills 0:04990d454f45 1941 /* printf(" client_IV:\t\t"); */
ashleymills 0:04990d454f45 1942 /* dump(dtls_kb_client_iv(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1943 /* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1944 /* printf("\n"); */
ashleymills 0:04990d454f45 1945
ashleymills 0:04990d454f45 1946 /* printf(" server_IV:\t\t"); */
ashleymills 0:04990d454f45 1947 /* dump(dtls_kb_server_iv(CURRENT_CONFIG(peer)), */
ashleymills 0:04990d454f45 1948 /* dtls_kb_iv_size(CURRENT_CONFIG(peer))); */
ashleymills 0:04990d454f45 1949 /* printf("\n"); */
ashleymills 0:04990d454f45 1950
ashleymills 0:04990d454f45 1951
ashleymills 0:04990d454f45 1952 /* } */
ashleymills 0:04990d454f45 1953 /* #endif */
ashleymills 0:04990d454f45 1954
ashleymills 0:04990d454f45 1955 return 1;
ashleymills 0:04990d454f45 1956 }
ashleymills 0:04990d454f45 1957
ashleymills 0:04990d454f45 1958 /**
ashleymills 0:04990d454f45 1959 * Handles incoming Alert messages. This function returns \c 1 if the
ashleymills 0:04990d454f45 1960 * connection should be closed and the peer is to be invalidated.
ashleymills 0:04990d454f45 1961 */
ashleymills 0:04990d454f45 1962 int
ashleymills 0:04990d454f45 1963 handle_alert(dtls_context_t *ctx, dtls_peer_t *peer,
ashleymills 0:04990d454f45 1964 uint8 *record_header, uint8 *data, size_t data_length) {
ashleymills 0:04990d454f45 1965 int free_peer = 0; /* indicates whether to free peer */
ashleymills 0:04990d454f45 1966
ashleymills 0:04990d454f45 1967 if (data_length < 2)
ashleymills 0:04990d454f45 1968 return 0;
ashleymills 0:04990d454f45 1969
ashleymills 0:04990d454f45 1970 INFO("** Alert: level %d, description %d\n", data[0], data[1]);
ashleymills 0:04990d454f45 1971
ashleymills 0:04990d454f45 1972 /* The peer object is invalidated for FATAL alerts and close
ashleymills 0:04990d454f45 1973 * notifies. This is done in two steps.: First, remove the object
ashleymills 0:04990d454f45 1974 * from our list of peers. After that, the event handler callback is
ashleymills 0:04990d454f45 1975 * invoked with the still existing peer object. Finally, the storage
ashleymills 0:04990d454f45 1976 * used by peer is released.
ashleymills 0:04990d454f45 1977 */
ashleymills 0:04990d454f45 1978 if (data[0] == DTLS_ALERT_LEVEL_FATAL || data[1] == DTLS_ALERT_CLOSE) {
ashleymills 1:bc8a649bad13 1979 INFO("%d invalidate peer\n", data[1]);
ashleymills 0:04990d454f45 1980
ashleymills 0:04990d454f45 1981 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 1982 HASH_DEL_PEER(ctx->peers, peer);
ashleymills 0:04990d454f45 1983 #else /* WITH_CONTIKI */
ashleymills 0:04990d454f45 1984 list_remove(ctx->peers, peer);
ashleymills 0:04990d454f45 1985
ashleymills 0:04990d454f45 1986 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 1987 /* PRINTF("removed peer ["); */
ashleymills 0:04990d454f45 1988 /* PRINT6ADDR(&peer->session.addr); */
ashleymills 0:04990d454f45 1989 /* PRINTF("]:%d\n", uip_ntohs(peer->session.port)); */
ashleymills 0:04990d454f45 1990 /* #endif */
ashleymills 0:04990d454f45 1991 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 1992
ashleymills 0:04990d454f45 1993 free_peer = 1;
ashleymills 0:04990d454f45 1994
ashleymills 0:04990d454f45 1995 }
ashleymills 0:04990d454f45 1996
ashleymills 0:04990d454f45 1997 (void)CALL(ctx, event, &peer->session,
ashleymills 0:04990d454f45 1998 (dtls_alert_level_t)data[0], (unsigned short)data[1]);
ashleymills 0:04990d454f45 1999 switch (data[1]) {
ashleymills 0:04990d454f45 2000 case DTLS_ALERT_CLOSE:
ashleymills 0:04990d454f45 2001 /* If state is DTLS_STATE_CLOSING, we have already sent a
ashleymills 0:04990d454f45 2002 * close_notify so, do not send that again. */
ashleymills 0:04990d454f45 2003 if (peer->state != DTLS_STATE_CLOSING) {
ashleymills 0:04990d454f45 2004 peer->state = DTLS_STATE_CLOSING;
ashleymills 0:04990d454f45 2005 dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_CLOSE);
ashleymills 0:04990d454f45 2006 } else
ashleymills 0:04990d454f45 2007 peer->state = DTLS_STATE_CLOSED;
ashleymills 0:04990d454f45 2008 break;
ashleymills 0:04990d454f45 2009 default:
ashleymills 0:04990d454f45 2010 ;
ashleymills 0:04990d454f45 2011 }
ashleymills 0:04990d454f45 2012
ashleymills 0:04990d454f45 2013 if (free_peer) {
ashleymills 0:04990d454f45 2014 dtls_stop_retransmission(ctx, peer);
ashleymills 0:04990d454f45 2015 dtls_free_peer(peer);
ashleymills 0:04990d454f45 2016 }
ashleymills 0:04990d454f45 2017
ashleymills 0:04990d454f45 2018 return free_peer;
ashleymills 0:04990d454f45 2019 }
ashleymills 0:04990d454f45 2020
ashleymills 0:04990d454f45 2021 /**
ashleymills 0:04990d454f45 2022 * Handles incoming data as DTLS message from given peer.
ashleymills 0:04990d454f45 2023 */
ashleymills 0:04990d454f45 2024 int dtls_handle_message(
ashleymills 0:04990d454f45 2025 dtls_context_t *ctx,
ashleymills 0:04990d454f45 2026 session_t *session,
ashleymills 0:04990d454f45 2027 uint8 *msg,
ashleymills 0:04990d454f45 2028 int msglen) {
ashleymills 0:04990d454f45 2029
ashleymills 0:04990d454f45 2030 DBG("dtls_handle_message");
ashleymills 0:04990d454f45 2031 dtls_peer_t *peer = NULL;
ashleymills 0:04990d454f45 2032 unsigned int rlen; /* record length */
ashleymills 0:04990d454f45 2033 uint8 *data; /* (decrypted) payload */
ashleymills 0:04990d454f45 2034 size_t data_length; /* length of decrypted payload
ashleymills 0:04990d454f45 2035 (without MAC and padding) */
ashleymills 0:04990d454f45 2036
ashleymills 0:04990d454f45 2037 /* check if we have DTLS state for addr/port/ifindex */
ashleymills 0:04990d454f45 2038
ashleymills 1:bc8a649bad13 2039 DBG("Check for cached DTLS state for addr/port/ifindex");
ashleymills 0:04990d454f45 2040 peer = dtls_get_peer(ctx, session);
ashleymills 0:04990d454f45 2041
ashleymills 0:04990d454f45 2042 #ifndef NDEBUG
ashleymills 0:04990d454f45 2043 if (peer) {
ashleymills 0:04990d454f45 2044 unsigned char addrbuf[72];
ashleymills 0:04990d454f45 2045
ashleymills 0:04990d454f45 2046 dsrv_print_addr(session, addrbuf, sizeof(addrbuf));
ashleymills 1:bc8a649bad13 2047 DBG("Found peer \"%s\"", addrbuf);
ashleymills 0:04990d454f45 2048 }
ashleymills 0:04990d454f45 2049 #endif /* NDEBUG */
ashleymills 0:04990d454f45 2050
ashleymills 0:04990d454f45 2051 if (!peer) {
ashleymills 1:bc8a649bad13 2052 DBG("No peer found.");
ashleymills 0:04990d454f45 2053 /* get first record from client message */
ashleymills 0:04990d454f45 2054 rlen = is_record(msg, msglen);
ashleymills 0:04990d454f45 2055 assert(rlen <= msglen);
ashleymills 0:04990d454f45 2056
ashleymills 0:04990d454f45 2057 if (!rlen) {
ashleymills 0:04990d454f45 2058 #ifndef NDEBUG
ashleymills 0:04990d454f45 2059 if (msglen > 3)
ashleymills 1:bc8a649bad13 2060 DBG("Dropped invalid message %02x%02x%02x%02x", msg[0], msg[1], msg[2], msg[3]);
ashleymills 0:04990d454f45 2061 else
ashleymills 1:bc8a649bad13 2062 DBG("Dropped invalid message (less than four bytes)");
ashleymills 0:04990d454f45 2063 #endif
ashleymills 0:04990d454f45 2064 return 0;
ashleymills 0:04990d454f45 2065 }
ashleymills 0:04990d454f45 2066
ashleymills 0:04990d454f45 2067 /* is_record() ensures that msg contains at least a record header */
ashleymills 0:04990d454f45 2068 data = msg + DTLS_RH_LENGTH;
ashleymills 0:04990d454f45 2069 data_length = rlen - DTLS_RH_LENGTH;
ashleymills 0:04990d454f45 2070
ashleymills 0:04990d454f45 2071 /* When no DTLS state exists for this peer, we only allow a
ashleymills 0:04990d454f45 2072 Client Hello message with
ashleymills 0:04990d454f45 2073
ashleymills 0:04990d454f45 2074 a) a valid cookie, or
ashleymills 0:04990d454f45 2075 b) no cookie.
ashleymills 0:04990d454f45 2076
ashleymills 0:04990d454f45 2077 Anything else will be rejected. Fragementation is not allowed
ashleymills 0:04990d454f45 2078 here as it would require peer state as well.
ashleymills 0:04990d454f45 2079 */
ashleymills 0:04990d454f45 2080
ashleymills 0:04990d454f45 2081 if (dtls_verify_peer(ctx, NULL, session, msg, data, data_length) <= 0) {
ashleymills 1:bc8a649bad13 2082 WARN("Cannot verify peer.");
ashleymills 0:04990d454f45 2083 return -1;
ashleymills 0:04990d454f45 2084 }
ashleymills 0:04990d454f45 2085
ashleymills 0:04990d454f45 2086 /* msg contains a Client Hello with a valid cookie, so we can
ashleymills 0:04990d454f45 2087 safely create the server state machine and continue with
ashleymills 0:04990d454f45 2088 the handshake. */
ashleymills 0:04990d454f45 2089
ashleymills 0:04990d454f45 2090 peer = dtls_new_peer(session);
ashleymills 0:04990d454f45 2091 if (!peer) {
ashleymills 1:bc8a649bad13 2092 DBG("Cannot create peer.");
ashleymills 0:04990d454f45 2093 /* FIXME: signal internal error */
ashleymills 0:04990d454f45 2094 return -1;
ashleymills 0:04990d454f45 2095 }
ashleymills 1:bc8a649bad13 2096 DBG("Created new peer.");
ashleymills 0:04990d454f45 2097
ashleymills 0:04990d454f45 2098 /* Initialize record sequence number to 1 for new peers. The first
ashleymills 0:04990d454f45 2099 * record with sequence number 0 is a stateless Hello Verify Request.
ashleymills 0:04990d454f45 2100 */
ashleymills 0:04990d454f45 2101 peer->rseq[5] = 1;
ashleymills 0:04990d454f45 2102
ashleymills 0:04990d454f45 2103 /* First negotiation step: check for PSK
ashleymills 0:04990d454f45 2104 *
ashleymills 0:04990d454f45 2105 * Note that we already have checked that msg is a Handshake
ashleymills 0:04990d454f45 2106 * message containing a ClientHello. dtls_get_cipher() therefore
ashleymills 0:04990d454f45 2107 * does not check again.
ashleymills 0:04990d454f45 2108 */
ashleymills 0:04990d454f45 2109 if (!dtls_update_parameters(ctx, peer,
ashleymills 0:04990d454f45 2110 msg + DTLS_RH_LENGTH, rlen - DTLS_RH_LENGTH)) {
ashleymills 0:04990d454f45 2111
ashleymills 1:bc8a649bad13 2112 WARN("Error updating security parameters");
ashleymills 0:04990d454f45 2113 /* FIXME: send handshake failure Alert */
ashleymills 0:04990d454f45 2114 dtls_alert(ctx, peer, DTLS_ALERT_LEVEL_FATAL,
ashleymills 0:04990d454f45 2115 DTLS_ALERT_HANDSHAKE_FAILURE);
ashleymills 0:04990d454f45 2116 dtls_free_peer(peer);
ashleymills 0:04990d454f45 2117 return -1;
ashleymills 0:04990d454f45 2118 }
ashleymills 0:04990d454f45 2119 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 2120 DBG("Adding peer to hash");
ashleymills 0:04990d454f45 2121 HASH_ADD_PEER(ctx->peers, session, peer);
ashleymills 0:04990d454f45 2122 #else /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2123 list_add(ctx->peers, peer);
ashleymills 0:04990d454f45 2124 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2125
ashleymills 0:04990d454f45 2126 /* update finish MAC */
ashleymills 0:04990d454f45 2127 update_hs_hash(peer, msg + DTLS_RH_LENGTH, rlen - DTLS_RH_LENGTH);
ashleymills 0:04990d454f45 2128
ashleymills 0:04990d454f45 2129 if (dtls_send_server_hello(ctx, peer) > 0)
ashleymills 0:04990d454f45 2130 peer->state = DTLS_STATE_SERVERHELLO;
ashleymills 0:04990d454f45 2131
ashleymills 0:04990d454f45 2132 /* after sending the ServerHelloDone, we expect the
ashleymills 0:04990d454f45 2133 * ClientKeyExchange (possibly containing the PSK id),
ashleymills 0:04990d454f45 2134 * followed by a ChangeCipherSpec and an encrypted Finished.
ashleymills 0:04990d454f45 2135 */
ashleymills 0:04990d454f45 2136
ashleymills 0:04990d454f45 2137 msg += rlen;
ashleymills 0:04990d454f45 2138 msglen -= rlen;
ashleymills 0:04990d454f45 2139 } else {
ashleymills 1:bc8a649bad13 2140 //DBG("Found peer");
ashleymills 0:04990d454f45 2141 }
ashleymills 0:04990d454f45 2142
ashleymills 0:04990d454f45 2143 /* At this point peer contains a state machine to handle the
ashleymills 0:04990d454f45 2144 received message. */
ashleymills 0:04990d454f45 2145
ashleymills 0:04990d454f45 2146 assert(peer);
ashleymills 0:04990d454f45 2147
ashleymills 0:04990d454f45 2148 /* FIXME: check sequence number of record and drop message if the
ashleymills 0:04990d454f45 2149 * number is not exactly the last number that we have responded to + 1.
ashleymills 0:04990d454f45 2150 * Otherwise, stop retransmissions for this specific peer and
ashleymills 0:04990d454f45 2151 * continue processing. */
ashleymills 0:04990d454f45 2152 dtls_stop_retransmission(ctx, peer);
ashleymills 0:04990d454f45 2153
ashleymills 0:04990d454f45 2154 while ((rlen = is_record(msg,msglen))) {
ashleymills 0:04990d454f45 2155
ashleymills 1:bc8a649bad13 2156 DBG("Got packet %d (%d bytes)", msg[0], rlen);
ashleymills 0:04990d454f45 2157 /* skip packet if it is from a different epoch */
ashleymills 0:04990d454f45 2158 if (memcmp(DTLS_RECORD_HEADER(msg)->epoch,
ashleymills 0:04990d454f45 2159 peer->epoch, sizeof(uint16)) != 0)
ashleymills 0:04990d454f45 2160 goto next;
ashleymills 0:04990d454f45 2161
ashleymills 0:04990d454f45 2162 if (!decrypt_verify(peer, msg, rlen, &data, &data_length)) {
ashleymills 1:bc8a649bad13 2163 INFO("decrypt_verify() failed");
ashleymills 0:04990d454f45 2164 goto next;
ashleymills 0:04990d454f45 2165 }
ashleymills 0:04990d454f45 2166
ashleymills 0:04990d454f45 2167 /* #ifndef NDEBUG */
ashleymills 0:04990d454f45 2168 /* hexdump(msg, sizeof(dtls_record_header_t)); */
ashleymills 0:04990d454f45 2169 /* printf("\n"); */
ashleymills 0:04990d454f45 2170 /* hexdump(data, data_length); */
ashleymills 0:04990d454f45 2171 /* printf("\n"); */
ashleymills 0:04990d454f45 2172 /* #endif */
ashleymills 0:04990d454f45 2173
ashleymills 0:04990d454f45 2174 /* Handle received record according to the first byte of the
ashleymills 0:04990d454f45 2175 * message, i.e. the subprotocol. We currently do not support
ashleymills 0:04990d454f45 2176 * combining multiple fragments of one type into a single
ashleymills 0:04990d454f45 2177 * record. */
ashleymills 0:04990d454f45 2178
ashleymills 0:04990d454f45 2179 switch (msg[0]) {
ashleymills 0:04990d454f45 2180
ashleymills 0:04990d454f45 2181 case DTLS_CT_CHANGE_CIPHER_SPEC:
ashleymills 0:04990d454f45 2182 handle_ccs(ctx, peer, msg, data, data_length);
ashleymills 0:04990d454f45 2183 break;
ashleymills 0:04990d454f45 2184
ashleymills 0:04990d454f45 2185 case DTLS_CT_ALERT:
ashleymills 0:04990d454f45 2186 if (handle_alert(ctx, peer, msg, data, data_length)) {
ashleymills 0:04990d454f45 2187 /* handle alert has invalidated peer */
ashleymills 0:04990d454f45 2188 peer = NULL;
ashleymills 0:04990d454f45 2189 return 0;
ashleymills 0:04990d454f45 2190 }
ashleymills 0:04990d454f45 2191
ashleymills 0:04990d454f45 2192 case DTLS_CT_HANDSHAKE:
ashleymills 0:04990d454f45 2193 DBG("case DTLS_CT_HANDSHAKE");
ashleymills 0:04990d454f45 2194 handle_handshake(ctx, peer, msg, data, data_length);
ashleymills 0:04990d454f45 2195 if (peer->state == DTLS_STATE_CONNECTED) {
ashleymills 0:04990d454f45 2196 /* stop retransmissions */
ashleymills 0:04990d454f45 2197 dtls_stop_retransmission(ctx, peer);
ashleymills 0:04990d454f45 2198 CALL(ctx, event, &peer->session, 0, DTLS_EVENT_CONNECTED);
ashleymills 0:04990d454f45 2199 }
ashleymills 0:04990d454f45 2200 break;
ashleymills 0:04990d454f45 2201
ashleymills 0:04990d454f45 2202 case DTLS_CT_APPLICATION_DATA:
ashleymills 1:bc8a649bad13 2203 INFO("** application data:");
ashleymills 0:04990d454f45 2204 CALL(ctx, read, &peer->session, data, data_length);
ashleymills 0:04990d454f45 2205 break;
ashleymills 0:04990d454f45 2206 default:
ashleymills 1:bc8a649bad13 2207 INFO("dropped unknown message of type %d",msg[0]);
ashleymills 0:04990d454f45 2208 }
ashleymills 0:04990d454f45 2209
ashleymills 0:04990d454f45 2210 next:
ashleymills 0:04990d454f45 2211 /* advance msg by length of ciphertext */
ashleymills 0:04990d454f45 2212 msg += rlen;
ashleymills 0:04990d454f45 2213 msglen -= rlen;
ashleymills 0:04990d454f45 2214 }
ashleymills 0:04990d454f45 2215
ashleymills 0:04990d454f45 2216 return 0;
ashleymills 0:04990d454f45 2217 }
ashleymills 0:04990d454f45 2218
ashleymills 0:04990d454f45 2219 dtls_context_t *
ashleymills 0:04990d454f45 2220 dtls_new_context(void *app_data) {
ashleymills 0:04990d454f45 2221 dtls_context_t *c;
ashleymills 0:04990d454f45 2222 dtls_tick_t now;
ashleymills 0:04990d454f45 2223 // XXX there is no /dev/urandom so this needs to be sorted
ashleymills 0:04990d454f45 2224 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 2225 FILE *urandom = fopen("/dev/urandom", "r");
ashleymills 0:04990d454f45 2226 unsigned char buf[sizeof(unsigned long)];
ashleymills 0:04990d454f45 2227 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2228
ashleymills 0:04990d454f45 2229 dtls_ticks(&now);
ashleymills 0:04990d454f45 2230 #ifdef WITH_CONTIKI
ashleymills 0:04990d454f45 2231 /* FIXME: need something better to init PRNG here */
ashleymills 0:04990d454f45 2232 prng_init(now);
ashleymills 0:04990d454f45 2233 #else /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2234
ashleymills 0:04990d454f45 2235 // urandom is only used to init a buffer, XXX fixme too
ashleymills 0:04990d454f45 2236 // need a decent urandom
ashleymills 0:04990d454f45 2237 /*
ashleymills 0:04990d454f45 2238
ashleymills 0:04990d454f45 2239 if (!urandom) {
ashleymills 0:04990d454f45 2240 dsrv_log(LOG_EMERG, "cannot initialize PRNG\n");
ashleymills 0:04990d454f45 2241 return NULL;
ashleymills 0:04990d454f45 2242 }
ashleymills 0:04990d454f45 2243
ashleymills 0:04990d454f45 2244 if (fread(buf, 1, sizeof(buf), urandom) != sizeof(buf)) {
ashleymills 0:04990d454f45 2245 dsrv_log(LOG_EMERG, "cannot initialize PRNG\n");
ashleymills 0:04990d454f45 2246 return NULL;
ashleymills 0:04990d454f45 2247 }
ashleymills 0:04990d454f45 2248
ashleymills 0:04990d454f45 2249 fclose(urandom);
ashleymills 0:04990d454f45 2250 */
ashleymills 0:04990d454f45 2251 // just randomly flip some bits
ashleymills 0:04990d454f45 2252 unsigned long mask = 0x0000;
ashleymills 0:04990d454f45 2253 for(int i=0; i<sizeof(buf); i++) {
ashleymills 0:04990d454f45 2254 // XXX need to flip some bits
ashleymills 0:04990d454f45 2255 }
ashleymills 0:04990d454f45 2256 prng_init((unsigned long)*buf);
ashleymills 0:04990d454f45 2257 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2258
ashleymills 0:04990d454f45 2259 c = &the_dtls_context;
ashleymills 0:04990d454f45 2260
ashleymills 0:04990d454f45 2261 memset(c, 0, sizeof(dtls_context_t));
ashleymills 0:04990d454f45 2262 c->app = app_data;
ashleymills 0:04990d454f45 2263
ashleymills 0:04990d454f45 2264 LIST_STRUCT_INIT(c, sendqueue);
ashleymills 0:04990d454f45 2265
ashleymills 0:04990d454f45 2266 #ifdef WITH_CONTIKI
ashleymills 0:04990d454f45 2267 LIST_STRUCT_INIT(c, peers);
ashleymills 0:04990d454f45 2268 /* LIST_STRUCT_INIT(c, key_store); */
ashleymills 0:04990d454f45 2269
ashleymills 0:04990d454f45 2270 process_start(&dtls_retransmit_process, (char *)c);
ashleymills 0:04990d454f45 2271 PROCESS_CONTEXT_BEGIN(&dtls_retransmit_process);
ashleymills 0:04990d454f45 2272 /* the retransmit timer must be initialized to some large value */
ashleymills 0:04990d454f45 2273 etimer_set(&c->retransmit_timer, 0xFFFF);
ashleymills 0:04990d454f45 2274 PROCESS_CONTEXT_END(&coap_retransmit_process);
ashleymills 0:04990d454f45 2275 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2276
ashleymills 0:04990d454f45 2277 if (prng(c->cookie_secret, DTLS_COOKIE_SECRET_LENGTH))
ashleymills 0:04990d454f45 2278 c->cookie_secret_age = now;
ashleymills 0:04990d454f45 2279 else
ashleymills 0:04990d454f45 2280 goto error;
ashleymills 0:04990d454f45 2281
ashleymills 0:04990d454f45 2282 return c;
ashleymills 0:04990d454f45 2283
ashleymills 0:04990d454f45 2284 error:
ashleymills 1:bc8a649bad13 2285 INFO("Cannot create DTLS context. Fail.");
ashleymills 0:04990d454f45 2286 if (c)
ashleymills 0:04990d454f45 2287 dtls_free_context(c);
ashleymills 0:04990d454f45 2288 return NULL;
ashleymills 0:04990d454f45 2289 }
ashleymills 0:04990d454f45 2290
ashleymills 0:04990d454f45 2291 void dtls_free_context(dtls_context_t *ctx) {
ashleymills 0:04990d454f45 2292 dtls_peer_t *p;
ashleymills 0:04990d454f45 2293
ashleymills 0:04990d454f45 2294 #ifndef WITH_CONTIKI
ashleymills 0:04990d454f45 2295 dtls_peer_t *tmp;
ashleymills 0:04990d454f45 2296
ashleymills 0:04990d454f45 2297 if (ctx->peers) {
ashleymills 0:04990d454f45 2298 HASH_ITER(hh, ctx->peers, p, tmp) {
ashleymills 0:04990d454f45 2299 dtls_free_peer(p);
ashleymills 0:04990d454f45 2300 }
ashleymills 0:04990d454f45 2301 }
ashleymills 0:04990d454f45 2302 #else /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2303 int i;
ashleymills 0:04990d454f45 2304
ashleymills 0:04990d454f45 2305 p = (dtls_peer_t *)peer_storage.mem;
ashleymills 0:04990d454f45 2306 for (i = 0; i < peer_storage.num; ++i, ++p) {
ashleymills 0:04990d454f45 2307 if (peer_storage.count[i])
ashleymills 0:04990d454f45 2308 dtls_free_peer(p);
ashleymills 0:04990d454f45 2309 }
ashleymills 0:04990d454f45 2310 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2311 }
ashleymills 0:04990d454f45 2312
ashleymills 0:04990d454f45 2313 int
ashleymills 0:04990d454f45 2314 dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer) {
ashleymills 0:04990d454f45 2315 uint8 *p = ctx->sendbuf;
ashleymills 0:04990d454f45 2316 size_t size;
ashleymills 0:04990d454f45 2317 int res;
ashleymills 0:04990d454f45 2318 dtls_tick_t now;
ashleymills 0:04990d454f45 2319
ashleymills 0:04990d454f45 2320 assert(peer);
ashleymills 0:04990d454f45 2321 if (!peer)
ashleymills 0:04990d454f45 2322 return -1;
ashleymills 0:04990d454f45 2323
ashleymills 0:04990d454f45 2324 /* check if the same peer is already in our list */
ashleymills 0:04990d454f45 2325 if (peer == dtls_get_peer(ctx, &peer->session)) {
ashleymills 1:bc8a649bad13 2326 DBG("Found peer, try to re-connect");
ashleymills 0:04990d454f45 2327 /* FIXME: send HelloRequest if we are server,
ashleymills 0:04990d454f45 2328 ClientHello with good cookie if client */
ashleymills 0:04990d454f45 2329 return 0;
ashleymills 0:04990d454f45 2330 }
ashleymills 0:04990d454f45 2331
ashleymills 0:04990d454f45 2332 /* set peer role to server: */
ashleymills 0:04990d454f45 2333 OTHER_CONFIG(peer)->role = DTLS_SERVER;
ashleymills 0:04990d454f45 2334 CURRENT_CONFIG(peer)->role = DTLS_SERVER;
ashleymills 0:04990d454f45 2335
ashleymills 0:04990d454f45 2336 dtls_add_peer(ctx, peer);
ashleymills 0:04990d454f45 2337
ashleymills 0:04990d454f45 2338 /* send ClientHello with some Cookie */
ashleymills 0:04990d454f45 2339
ashleymills 0:04990d454f45 2340 /* add to size:
ashleymills 0:04990d454f45 2341 * 1. length of session id (including length field)
ashleymills 0:04990d454f45 2342 * 2. length of cookie (including length field)
ashleymills 0:04990d454f45 2343 * 3. cypher suites
ashleymills 0:04990d454f45 2344 * 4. compression methods
ashleymills 0:04990d454f45 2345 */
ashleymills 0:04990d454f45 2346 size = DTLS_CH_LENGTH + 8;
ashleymills 0:04990d454f45 2347
ashleymills 0:04990d454f45 2348 /* force sending 0 as handshake message sequence number by setting
ashleymills 0:04990d454f45 2349 * peer to NULL */
ashleymills 0:04990d454f45 2350 p = dtls_set_handshake_header(DTLS_HT_CLIENT_HELLO, NULL,
ashleymills 0:04990d454f45 2351 size, 0, size, p);
ashleymills 0:04990d454f45 2352
ashleymills 0:04990d454f45 2353 dtls_int_to_uint16(p, DTLS_VERSION);
ashleymills 0:04990d454f45 2354 p += sizeof(uint16);
ashleymills 0:04990d454f45 2355
ashleymills 0:04990d454f45 2356 dtls_ticks(&now);
ashleymills 0:04990d454f45 2357 /* Set client random: First 4 bytes are the client's Unix timestamp,
ashleymills 0:04990d454f45 2358 * followed by 28 bytes of generate random data. */
ashleymills 0:04990d454f45 2359 dtls_int_to_uint32(&OTHER_CONFIG(peer)->client_random,
ashleymills 0:04990d454f45 2360 now / DTLS_TICKS_PER_SECOND);
ashleymills 0:04990d454f45 2361 prng(OTHER_CONFIG(peer)->client_random + sizeof(uint32),
ashleymills 0:04990d454f45 2362 sizeof(OTHER_CONFIG(peer)->client_random) - sizeof(uint32));
ashleymills 0:04990d454f45 2363 memcpy(p, OTHER_CONFIG(peer)->client_random,
ashleymills 0:04990d454f45 2364 sizeof(OTHER_CONFIG(peer)->client_random));
ashleymills 0:04990d454f45 2365 p += 32;
ashleymills 0:04990d454f45 2366
ashleymills 0:04990d454f45 2367 /* session id (length 0) */
ashleymills 0:04990d454f45 2368 dtls_int_to_uint8(p, 0);
ashleymills 0:04990d454f45 2369 p += sizeof(uint8);
ashleymills 0:04990d454f45 2370
ashleymills 0:04990d454f45 2371 dtls_int_to_uint8(p, 0);
ashleymills 0:04990d454f45 2372 p += sizeof(uint8);
ashleymills 0:04990d454f45 2373
ashleymills 0:04990d454f45 2374 /* add supported cipher suite */
ashleymills 0:04990d454f45 2375 dtls_int_to_uint16(p, 2);
ashleymills 0:04990d454f45 2376 p += sizeof(uint16);
ashleymills 0:04990d454f45 2377
ashleymills 0:04990d454f45 2378 dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8);
ashleymills 0:04990d454f45 2379 p += sizeof(uint16);
ashleymills 0:04990d454f45 2380
ashleymills 0:04990d454f45 2381 /* compression method */
ashleymills 0:04990d454f45 2382 dtls_int_to_uint8(p, 1);
ashleymills 0:04990d454f45 2383 p += sizeof(uint8);
ashleymills 0:04990d454f45 2384
ashleymills 0:04990d454f45 2385 dtls_int_to_uint8(p, TLS_COMP_NULL);
ashleymills 0:04990d454f45 2386 p += sizeof(uint8);
ashleymills 0:04990d454f45 2387
ashleymills 0:04990d454f45 2388 res = dtls_send(ctx, peer, DTLS_CT_HANDSHAKE, ctx->sendbuf,
ashleymills 0:04990d454f45 2389 p - ctx->sendbuf);
ashleymills 0:04990d454f45 2390 if (res < 0)
ashleymills 1:bc8a649bad13 2391 WARN("Cannot send ClientHello");
ashleymills 0:04990d454f45 2392 else
ashleymills 0:04990d454f45 2393 peer->state = DTLS_STATE_CLIENTHELLO;
ashleymills 0:04990d454f45 2394
ashleymills 0:04990d454f45 2395 DBG("Sent client hello");
ashleymills 0:04990d454f45 2396 return res;
ashleymills 0:04990d454f45 2397 }
ashleymills 0:04990d454f45 2398
ashleymills 0:04990d454f45 2399 int
ashleymills 0:04990d454f45 2400 dtls_connect(dtls_context_t *ctx, const session_t *dst) {
ashleymills 0:04990d454f45 2401 DBG("dtls_connect");
ashleymills 0:04990d454f45 2402 dtls_peer_t *peer;
ashleymills 0:04990d454f45 2403
ashleymills 0:04990d454f45 2404 peer = dtls_get_peer(ctx, dst);
ashleymills 0:04990d454f45 2405
ashleymills 0:04990d454f45 2406 if (!peer)
ashleymills 0:04990d454f45 2407 peer = dtls_new_peer(dst);
ashleymills 0:04990d454f45 2408
ashleymills 0:04990d454f45 2409 DBG("Created new peer as it didn't exist.");
ashleymills 0:04990d454f45 2410
ashleymills 0:04990d454f45 2411 if (!peer) {
ashleymills 0:04990d454f45 2412 DBG("Cannot create new peer, bailing.");
ashleymills 0:04990d454f45 2413 return -1;
ashleymills 0:04990d454f45 2414 }
ashleymills 0:04990d454f45 2415
ashleymills 0:04990d454f45 2416 return dtls_connect_peer(ctx, peer);
ashleymills 0:04990d454f45 2417 }
ashleymills 0:04990d454f45 2418
ashleymills 0:04990d454f45 2419 void
ashleymills 0:04990d454f45 2420 dtls_retransmit(dtls_context_t *context, netq_t *node) {
ashleymills 0:04990d454f45 2421 if (!context || !node)
ashleymills 0:04990d454f45 2422 return;
ashleymills 0:04990d454f45 2423
ashleymills 0:04990d454f45 2424 /* re-initialize timeout when maximum number of retransmissions are not reached yet */
ashleymills 0:04990d454f45 2425 if (node->retransmit_cnt < DTLS_DEFAULT_MAX_RETRANSMIT) {
ashleymills 0:04990d454f45 2426 unsigned char sendbuf[DTLS_MAX_BUF];
ashleymills 0:04990d454f45 2427 size_t len = sizeof(sendbuf);
ashleymills 0:04990d454f45 2428
ashleymills 0:04990d454f45 2429 node->retransmit_cnt++;
ashleymills 0:04990d454f45 2430 node->t += (node->timeout << node->retransmit_cnt);
ashleymills 0:04990d454f45 2431 netq_insert_node((netq_t **)context->sendqueue, node);
ashleymills 0:04990d454f45 2432
ashleymills 1:bc8a649bad13 2433 DBG("** retransmit packet");
ashleymills 0:04990d454f45 2434
ashleymills 0:04990d454f45 2435 if (dtls_prepare_record(node->peer, DTLS_CT_HANDSHAKE,
ashleymills 0:04990d454f45 2436 node->data, node->length,
ashleymills 0:04990d454f45 2437 sendbuf, &len) > 0) {
ashleymills 0:04990d454f45 2438
ashleymills 0:04990d454f45 2439 #ifndef NDEBUG
ashleymills 0:04990d454f45 2440 if (dtls_get_log_level() >= LOG_DEBUG) {
ashleymills 1:bc8a649bad13 2441 DBG("retransmit %d bytes", len);
ashleymills 0:04990d454f45 2442 hexdump(sendbuf, sizeof(dtls_record_header_t));
ashleymills 1:bc8a649bad13 2443 DBGX("\r\n");
ashleymills 0:04990d454f45 2444 hexdump(node->data, node->length);
ashleymills 1:bc8a649bad13 2445 DBGX("\r\n");
ashleymills 0:04990d454f45 2446 }
ashleymills 0:04990d454f45 2447 #endif
ashleymills 0:04990d454f45 2448
ashleymills 0:04990d454f45 2449 (void)CALL(context, write, &node->peer->session, sendbuf, len);
ashleymills 0:04990d454f45 2450 }
ashleymills 0:04990d454f45 2451 return;
ashleymills 0:04990d454f45 2452 }
ashleymills 0:04990d454f45 2453
ashleymills 0:04990d454f45 2454 /* no more retransmissions, remove node from system */
ashleymills 0:04990d454f45 2455
ashleymills 1:bc8a649bad13 2456 DBG("** removed transaction");
ashleymills 0:04990d454f45 2457
ashleymills 0:04990d454f45 2458 /* And finally delete the node */
ashleymills 0:04990d454f45 2459 netq_node_free(node);
ashleymills 0:04990d454f45 2460 }
ashleymills 0:04990d454f45 2461
ashleymills 0:04990d454f45 2462 void
ashleymills 0:04990d454f45 2463 dtls_stop_retransmission(dtls_context_t *context, dtls_peer_t *peer) {
ashleymills 0:04990d454f45 2464 void *node;
ashleymills 0:04990d454f45 2465 node = list_head((list_t)context->sendqueue);
ashleymills 0:04990d454f45 2466
ashleymills 0:04990d454f45 2467 while (node) {
ashleymills 0:04990d454f45 2468 if (dtls_session_equals(&((netq_t *)node)->peer->session,
ashleymills 0:04990d454f45 2469 &peer->session)) {
ashleymills 0:04990d454f45 2470 void *tmp = node;
ashleymills 0:04990d454f45 2471 node = list_item_next(node);
ashleymills 0:04990d454f45 2472 list_remove((list_t)context->sendqueue, tmp);
ashleymills 0:04990d454f45 2473 netq_node_free((netq_t *)tmp);
ashleymills 0:04990d454f45 2474 } else
ashleymills 0:04990d454f45 2475 node = list_item_next(node);
ashleymills 0:04990d454f45 2476 }
ashleymills 0:04990d454f45 2477 }
ashleymills 0:04990d454f45 2478
ashleymills 0:04990d454f45 2479 void
ashleymills 0:04990d454f45 2480 dtls_check_retransmit(dtls_context_t *context, clock_time_t *next) {
ashleymills 0:04990d454f45 2481 dtls_tick_t now;
ashleymills 0:04990d454f45 2482 netq_t *node = netq_head((netq_t **)context->sendqueue);
ashleymills 0:04990d454f45 2483
ashleymills 0:04990d454f45 2484 dtls_ticks(&now);
ashleymills 0:04990d454f45 2485 while (node && node->t <= now) {
ashleymills 0:04990d454f45 2486 netq_pop_first((netq_t **)context->sendqueue);
ashleymills 0:04990d454f45 2487 dtls_retransmit(context, node);
ashleymills 0:04990d454f45 2488 node = netq_head((netq_t **)context->sendqueue);
ashleymills 0:04990d454f45 2489 }
ashleymills 0:04990d454f45 2490
ashleymills 0:04990d454f45 2491 if (next && node)
ashleymills 0:04990d454f45 2492 *next = node->t;
ashleymills 0:04990d454f45 2493 }
ashleymills 0:04990d454f45 2494
ashleymills 0:04990d454f45 2495 #ifdef WITH_CONTIKI
ashleymills 0:04990d454f45 2496 /*---------------------------------------------------------------------------*/
ashleymills 0:04990d454f45 2497 /* message retransmission */
ashleymills 0:04990d454f45 2498 /*---------------------------------------------------------------------------*/
ashleymills 0:04990d454f45 2499 PROCESS_THREAD(dtls_retransmit_process, ev, data)
ashleymills 0:04990d454f45 2500 {
ashleymills 0:04990d454f45 2501 clock_time_t now;
ashleymills 0:04990d454f45 2502 netq_t *node;
ashleymills 0:04990d454f45 2503
ashleymills 0:04990d454f45 2504 PROCESS_BEGIN();
ashleymills 0:04990d454f45 2505
ashleymills 1:bc8a649bad13 2506 DBG("Started DTLS retransmit process");
ashleymills 0:04990d454f45 2507
ashleymills 0:04990d454f45 2508 while(1) {
ashleymills 0:04990d454f45 2509 PROCESS_YIELD();
ashleymills 0:04990d454f45 2510 if (ev == PROCESS_EVENT_TIMER) {
ashleymills 0:04990d454f45 2511 if (etimer_expired(&the_dtls_context.retransmit_timer)) {
ashleymills 0:04990d454f45 2512
ashleymills 0:04990d454f45 2513 node = list_head(the_dtls_context.sendqueue);
ashleymills 0:04990d454f45 2514
ashleymills 0:04990d454f45 2515 now = clock_time();
ashleymills 0:04990d454f45 2516 while (node && node->t <= now) {
ashleymills 0:04990d454f45 2517 dtls_retransmit(&the_dtls_context, list_pop(the_dtls_context.sendqueue));
ashleymills 0:04990d454f45 2518 node = list_head(the_dtls_context.sendqueue);
ashleymills 0:04990d454f45 2519 }
ashleymills 0:04990d454f45 2520
ashleymills 0:04990d454f45 2521 /* need to set timer to some value even if no nextpdu is available */
ashleymills 0:04990d454f45 2522 etimer_set(&the_dtls_context.retransmit_timer,
ashleymills 0:04990d454f45 2523 node ? node->t - now : 0xFFFF);
ashleymills 0:04990d454f45 2524 }
ashleymills 0:04990d454f45 2525 }
ashleymills 0:04990d454f45 2526 }
ashleymills 0:04990d454f45 2527
ashleymills 0:04990d454f45 2528 PROCESS_END();
ashleymills 0:04990d454f45 2529 }
ashleymills 0:04990d454f45 2530 #endif /* WITH_CONTIKI */
ashleymills 0:04990d454f45 2531
ashleymills 0:04990d454f45 2532 #ifndef NDEBUG
ashleymills 0:04990d454f45 2533 /** dumps packets in usual hexdump format */
ashleymills 0:04990d454f45 2534 void hexdump(const unsigned char *packet, int length) {
ashleymills 0:04990d454f45 2535 int n = 0;
ashleymills 0:04990d454f45 2536
ashleymills 0:04990d454f45 2537 while (length--) {
ashleymills 0:04990d454f45 2538 if (n % 16 == 0)
ashleymills 0:04990d454f45 2539 printf("%08X ",n);
ashleymills 0:04990d454f45 2540
ashleymills 0:04990d454f45 2541 printf("%02X ", *packet++);
ashleymills 0:04990d454f45 2542
ashleymills 0:04990d454f45 2543 n++;
ashleymills 0:04990d454f45 2544 if (n % 8 == 0) {
ashleymills 0:04990d454f45 2545 if (n % 16 == 0)
ashleymills 1:bc8a649bad13 2546 printf("\r\n");
ashleymills 0:04990d454f45 2547 else
ashleymills 1:bc8a649bad13 2548 printf(" ");
ashleymills 0:04990d454f45 2549 }
ashleymills 0:04990d454f45 2550 }
ashleymills 0:04990d454f45 2551 }
ashleymills 0:04990d454f45 2552
ashleymills 0:04990d454f45 2553 /** dump as narrow string of hex digits */
ashleymills 0:04990d454f45 2554 void dump(unsigned char *buf, size_t len) {
ashleymills 0:04990d454f45 2555 while (len--)
ashleymills 0:04990d454f45 2556 printf("%02x", *buf++);
ashleymills 0:04990d454f45 2557 }
ashleymills 0:04990d454f45 2558 #endif
ashleymills 0:04990d454f45 2559