mbed port of tinydtls

Committer:
ashleymills
Date:
Thu Oct 10 21:38:07 2013 +0000
Revision:
0:04990d454f45
Child:
1:bc8a649bad13
It now works. Found nasty gotcha with non-std sockaddr_in

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