Version 0.5.0 of tinydtls

Dependents:   tinydtls_test_cellular tinydtls_test_ethernet tiny-dtls

Committer:
ashleymills
Date:
Wed Feb 12 09:30:16 2014 +0000
Revision:
1:598a56fe116e
Parent:
0:ff9ebe0cf0e9
Explicitly removed something instead of relying on MACRO to disable it. Mbed can't use it.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ashleymills 0:ff9ebe0cf0e9 1 /* dtls -- a very basic DTLS implementation
ashleymills 0:ff9ebe0cf0e9 2 *
ashleymills 0:ff9ebe0cf0e9 3 * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org>
ashleymills 0:ff9ebe0cf0e9 4 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
ashleymills 0:ff9ebe0cf0e9 5 *
ashleymills 0:ff9ebe0cf0e9 6 * Permission is hereby granted, free of charge, to any person
ashleymills 0:ff9ebe0cf0e9 7 * obtaining a copy of this software and associated documentation
ashleymills 0:ff9ebe0cf0e9 8 * files (the "Software"), to deal in the Software without
ashleymills 0:ff9ebe0cf0e9 9 * restriction, including without limitation the rights to use, copy,
ashleymills 0:ff9ebe0cf0e9 10 * modify, merge, publish, distribute, sublicense, and/or sell copies
ashleymills 0:ff9ebe0cf0e9 11 * of the Software, and to permit persons to whom the Software is
ashleymills 0:ff9ebe0cf0e9 12 * furnished to do so, subject to the following conditions:
ashleymills 0:ff9ebe0cf0e9 13 *
ashleymills 0:ff9ebe0cf0e9 14 * The above copyright notice and this permission notice shall be
ashleymills 0:ff9ebe0cf0e9 15 * included in all copies or substantial portions of the Software.
ashleymills 0:ff9ebe0cf0e9 16 *
ashleymills 0:ff9ebe0cf0e9 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
ashleymills 0:ff9ebe0cf0e9 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
ashleymills 0:ff9ebe0cf0e9 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ashleymills 0:ff9ebe0cf0e9 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
ashleymills 0:ff9ebe0cf0e9 21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ashleymills 0:ff9ebe0cf0e9 22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
ashleymills 0:ff9ebe0cf0e9 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
ashleymills 0:ff9ebe0cf0e9 24 * SOFTWARE.
ashleymills 0:ff9ebe0cf0e9 25 */
ashleymills 0:ff9ebe0cf0e9 26
ashleymills 0:ff9ebe0cf0e9 27 /**
ashleymills 0:ff9ebe0cf0e9 28 * @file dtls.h
ashleymills 0:ff9ebe0cf0e9 29 * @brief High level DTLS API and visible structures.
ashleymills 0:ff9ebe0cf0e9 30 */
ashleymills 0:ff9ebe0cf0e9 31
ashleymills 0:ff9ebe0cf0e9 32 #ifndef _DTLS_H_
ashleymills 0:ff9ebe0cf0e9 33 #define _DTLS_H_
ashleymills 0:ff9ebe0cf0e9 34
ashleymills 0:ff9ebe0cf0e9 35 #include <stdint.h>
ashleymills 0:ff9ebe0cf0e9 36
ashleymills 1:598a56fe116e 37 #define MBED
ashleymills 1:598a56fe116e 38
ashleymills 0:ff9ebe0cf0e9 39 #include "t_list.h"
ashleymills 0:ff9ebe0cf0e9 40 #include "state.h"
ashleymills 0:ff9ebe0cf0e9 41 #include "peer.h"
ashleymills 0:ff9ebe0cf0e9 42
ashleymills 0:ff9ebe0cf0e9 43 #ifndef WITH_CONTIKI
ashleymills 0:ff9ebe0cf0e9 44 #include "uthash.h"
ashleymills 0:ff9ebe0cf0e9 45 #include "t_list.h"
ashleymills 0:ff9ebe0cf0e9 46 #endif /* WITH_CONTIKI */
ashleymills 0:ff9ebe0cf0e9 47
ashleymills 0:ff9ebe0cf0e9 48 #include "alert.h"
ashleymills 0:ff9ebe0cf0e9 49 #include "crypto.h"
ashleymills 0:ff9ebe0cf0e9 50 #include "hmac.h"
ashleymills 0:ff9ebe0cf0e9 51
ashleymills 0:ff9ebe0cf0e9 52 #include "global.h"
ashleymills 0:ff9ebe0cf0e9 53 #include "dtls_time.h"
ashleymills 0:ff9ebe0cf0e9 54
ashleymills 0:ff9ebe0cf0e9 55 #ifndef DTLSv12
ashleymills 0:ff9ebe0cf0e9 56 #define DTLS_VERSION 0xfeff /* DTLS v1.1 */
ashleymills 0:ff9ebe0cf0e9 57 #else
ashleymills 0:ff9ebe0cf0e9 58 #define DTLS_VERSION 0xfefd /* DTLS v1.2 */
ashleymills 0:ff9ebe0cf0e9 59 #endif
ashleymills 0:ff9ebe0cf0e9 60
ashleymills 0:ff9ebe0cf0e9 61
ashleymills 0:ff9ebe0cf0e9 62
ashleymills 0:ff9ebe0cf0e9 63 /* This is the maximal supported length of the psk client identity and psk
ashleymills 0:ff9ebe0cf0e9 64 * server identity hint */
ashleymills 0:ff9ebe0cf0e9 65 #define DTLS_PSK_MAX_CLIENT_IDENTITY_LEN 32
ashleymills 0:ff9ebe0cf0e9 66
ashleymills 0:ff9ebe0cf0e9 67 typedef struct dtls_psk_key_t {
ashleymills 0:ff9ebe0cf0e9 68 unsigned char *id; /**< psk identity */
ashleymills 0:ff9ebe0cf0e9 69 size_t id_length; /**< length of psk identity */
ashleymills 0:ff9ebe0cf0e9 70 unsigned char *key; /**< key data */
ashleymills 0:ff9ebe0cf0e9 71 size_t key_length; /**< length of key */
ashleymills 0:ff9ebe0cf0e9 72 } dtls_psk_key_t;
ashleymills 0:ff9ebe0cf0e9 73
ashleymills 0:ff9ebe0cf0e9 74 typedef struct dtls_ecdsa_key_t {
ashleymills 0:ff9ebe0cf0e9 75 dtls_ecdh_curve curve;
ashleymills 0:ff9ebe0cf0e9 76 const unsigned char *priv_key; /** < private key as bytes > */
ashleymills 0:ff9ebe0cf0e9 77 const unsigned char *pub_key_x; /** < x part of the public key for the given private key > */
ashleymills 0:ff9ebe0cf0e9 78 const unsigned char *pub_key_y; /** < y part of the public key for the given private key > */
ashleymills 0:ff9ebe0cf0e9 79 } dtls_ecdsa_key_t;
ashleymills 0:ff9ebe0cf0e9 80
ashleymills 0:ff9ebe0cf0e9 81 /** Length of the secret that is used for generating Hello Verify cookies. */
ashleymills 0:ff9ebe0cf0e9 82 #define DTLS_COOKIE_SECRET_LENGTH 12
ashleymills 0:ff9ebe0cf0e9 83
ashleymills 0:ff9ebe0cf0e9 84 struct dtls_context_t;
ashleymills 0:ff9ebe0cf0e9 85
ashleymills 0:ff9ebe0cf0e9 86 #ifdef __cplusplus
ashleymills 0:ff9ebe0cf0e9 87 extern "C" {
ashleymills 0:ff9ebe0cf0e9 88 #endif
ashleymills 0:ff9ebe0cf0e9 89
ashleymills 0:ff9ebe0cf0e9 90 /**
ashleymills 0:ff9ebe0cf0e9 91 * This structure contains callback functions used by tinydtls to
ashleymills 0:ff9ebe0cf0e9 92 * communicate with the application. At least the write function must
ashleymills 0:ff9ebe0cf0e9 93 * be provided. It is called by the DTLS state machine to send packets
ashleymills 0:ff9ebe0cf0e9 94 * over the network. The read function is invoked to deliver decrypted
ashleymills 0:ff9ebe0cf0e9 95 * and verfified application data. The third callback is an event
ashleymills 0:ff9ebe0cf0e9 96 * handler function that is called when alert messages are encountered
ashleymills 0:ff9ebe0cf0e9 97 * or events generated by the library have occured.
ashleymills 0:ff9ebe0cf0e9 98 */
ashleymills 0:ff9ebe0cf0e9 99 typedef struct {
ashleymills 0:ff9ebe0cf0e9 100 /**
ashleymills 0:ff9ebe0cf0e9 101 * Called from dtls_handle_message() to send DTLS packets over the
ashleymills 0:ff9ebe0cf0e9 102 * network. The callback function must use the network interface
ashleymills 0:ff9ebe0cf0e9 103 * denoted by session->ifindex to send the data.
ashleymills 0:ff9ebe0cf0e9 104 *
ashleymills 0:ff9ebe0cf0e9 105 * @param ctx The current DTLS context.
ashleymills 0:ff9ebe0cf0e9 106 * @param session The session object, including the address of the
ashleymills 0:ff9ebe0cf0e9 107 * remote peer where the data shall be sent.
ashleymills 0:ff9ebe0cf0e9 108 * @param buf The data to send.
ashleymills 0:ff9ebe0cf0e9 109 * @param len The actual length of @p buf.
ashleymills 0:ff9ebe0cf0e9 110 * @return The callback function must return the number of bytes
ashleymills 0:ff9ebe0cf0e9 111 * that were sent, or a value less than zero to indicate an
ashleymills 0:ff9ebe0cf0e9 112 * error.
ashleymills 0:ff9ebe0cf0e9 113 */
ashleymills 0:ff9ebe0cf0e9 114 int (*write)(struct dtls_context_t *ctx,
ashleymills 0:ff9ebe0cf0e9 115 session_t *session, uint8 *buf, size_t len);
ashleymills 0:ff9ebe0cf0e9 116
ashleymills 0:ff9ebe0cf0e9 117 /**
ashleymills 0:ff9ebe0cf0e9 118 * Called from dtls_handle_message() deliver application data that was
ashleymills 0:ff9ebe0cf0e9 119 * received on the given session. The data is delivered only after
ashleymills 0:ff9ebe0cf0e9 120 * decryption and verification have succeeded.
ashleymills 0:ff9ebe0cf0e9 121 *
ashleymills 0:ff9ebe0cf0e9 122 * @param ctx The current DTLS context.
ashleymills 0:ff9ebe0cf0e9 123 * @param session The session object, including the address of the
ashleymills 0:ff9ebe0cf0e9 124 * data's origin.
ashleymills 0:ff9ebe0cf0e9 125 * @param buf The received data packet.
ashleymills 0:ff9ebe0cf0e9 126 * @param len The actual length of @p buf.
ashleymills 0:ff9ebe0cf0e9 127 * @return ignored
ashleymills 0:ff9ebe0cf0e9 128 */
ashleymills 0:ff9ebe0cf0e9 129 int (*read)(struct dtls_context_t *ctx,
ashleymills 0:ff9ebe0cf0e9 130 session_t *session, uint8 *buf, size_t len);
ashleymills 0:ff9ebe0cf0e9 131
ashleymills 0:ff9ebe0cf0e9 132 /**
ashleymills 0:ff9ebe0cf0e9 133 * The event handler is called when a message from the alert
ashleymills 0:ff9ebe0cf0e9 134 * protocol is received or the state of the DTLS session changes.
ashleymills 0:ff9ebe0cf0e9 135 *
ashleymills 0:ff9ebe0cf0e9 136 * @param ctx The current dtls context.
ashleymills 0:ff9ebe0cf0e9 137 * @param session The session object that was affected.
ashleymills 0:ff9ebe0cf0e9 138 * @param level The alert level or @c 0 when an event ocurred that
ashleymills 0:ff9ebe0cf0e9 139 * is not an alert.
ashleymills 0:ff9ebe0cf0e9 140 * @param code Values less than @c 256 indicate alerts, while
ashleymills 0:ff9ebe0cf0e9 141 * @c 256 or greater indicate internal DTLS session changes.
ashleymills 0:ff9ebe0cf0e9 142 * @return ignored
ashleymills 0:ff9ebe0cf0e9 143 */
ashleymills 0:ff9ebe0cf0e9 144 int (*event)(struct dtls_context_t *ctx, session_t *session,
ashleymills 0:ff9ebe0cf0e9 145 dtls_alert_level_t level, unsigned short code);
ashleymills 0:ff9ebe0cf0e9 146
ashleymills 0:ff9ebe0cf0e9 147 /**
ashleymills 0:ff9ebe0cf0e9 148 * Called during handshake to lookup the key for @p id in @p
ashleymills 0:ff9ebe0cf0e9 149 * session. If found, the key must be stored in @p result and
ashleymills 0:ff9ebe0cf0e9 150 * the return value must be @c 0. If not found, @p result is
ashleymills 0:ff9ebe0cf0e9 151 * undefined and the return value must be less than zero.
ashleymills 0:ff9ebe0cf0e9 152 * If PSK should not be supported, set this pointer to NULL.
ashleymills 0:ff9ebe0cf0e9 153 *
ashleymills 0:ff9ebe0cf0e9 154 * @param ctx The current dtls context.
ashleymills 0:ff9ebe0cf0e9 155 * @param session The session where the key will be used.
ashleymills 0:ff9ebe0cf0e9 156 * @param id The identity of the communicating peer. This value is
ashleymills 0:ff9ebe0cf0e9 157 * @c NULL when the DTLS engine requests the local
ashleymills 0:ff9ebe0cf0e9 158 * id/key pair to use for session setup.
ashleymills 0:ff9ebe0cf0e9 159 * @param id_len The actual length of @p id
ashleymills 0:ff9ebe0cf0e9 160 * @param result Must be set to the key object to use.for the given
ashleymills 0:ff9ebe0cf0e9 161 * session.
ashleymills 0:ff9ebe0cf0e9 162 * @return @c 0 if result is set, or less than zero on error.
ashleymills 0:ff9ebe0cf0e9 163 */
ashleymills 0:ff9ebe0cf0e9 164 int (*get_psk_key)(struct dtls_context_t *ctx,
ashleymills 0:ff9ebe0cf0e9 165 const session_t *session,
ashleymills 0:ff9ebe0cf0e9 166 const unsigned char *id, size_t id_len,
ashleymills 0:ff9ebe0cf0e9 167 const dtls_psk_key_t **result);
ashleymills 0:ff9ebe0cf0e9 168
ashleymills 0:ff9ebe0cf0e9 169 /**
ashleymills 0:ff9ebe0cf0e9 170 * Called during handshake to get the server's or client's ecdsa
ashleymills 0:ff9ebe0cf0e9 171 * key used to authenticate this server or client in this
ashleymills 0:ff9ebe0cf0e9 172 * session. If found, the key must be stored in @p result and
ashleymills 0:ff9ebe0cf0e9 173 * the return value must be @c 0. If not found, @p result is
ashleymills 0:ff9ebe0cf0e9 174 * undefined and the return value must be less than zero.
ashleymills 0:ff9ebe0cf0e9 175 *
ashleymills 0:ff9ebe0cf0e9 176 * If ECDSA should not be supported, set this pointer to NULL.
ashleymills 0:ff9ebe0cf0e9 177 *
ashleymills 0:ff9ebe0cf0e9 178 * Implement this if you want to provide your own certificate to
ashleymills 0:ff9ebe0cf0e9 179 * the other peer. This is mandatory for a server providing ECDSA
ashleymills 0:ff9ebe0cf0e9 180 * support and optional for a client. A client doing DTLS client
ashleymills 0:ff9ebe0cf0e9 181 * authentication has to implementing this callback.
ashleymills 0:ff9ebe0cf0e9 182 *
ashleymills 0:ff9ebe0cf0e9 183 * @param ctx The current dtls context.
ashleymills 0:ff9ebe0cf0e9 184 * @param session The session where the key will be used.
ashleymills 0:ff9ebe0cf0e9 185 * @param result Must be set to the key object to used for the given
ashleymills 0:ff9ebe0cf0e9 186 * session.
ashleymills 0:ff9ebe0cf0e9 187 * @return @c 0 if result is set, or less than zero on error.
ashleymills 0:ff9ebe0cf0e9 188 */
ashleymills 0:ff9ebe0cf0e9 189 int (*get_ecdsa_key)(struct dtls_context_t *ctx,
ashleymills 0:ff9ebe0cf0e9 190 const session_t *session,
ashleymills 0:ff9ebe0cf0e9 191 const dtls_ecdsa_key_t **result);
ashleymills 0:ff9ebe0cf0e9 192
ashleymills 0:ff9ebe0cf0e9 193 /**
ashleymills 0:ff9ebe0cf0e9 194 * Called during handshake to check the peer's pubic key in this
ashleymills 0:ff9ebe0cf0e9 195 * session. If the public key matches the session and should be
ashleymills 0:ff9ebe0cf0e9 196 * considerated valid the return value must be @c 0. If not valid,
ashleymills 0:ff9ebe0cf0e9 197 * the return value must be less than zero.
ashleymills 0:ff9ebe0cf0e9 198 *
ashleymills 0:ff9ebe0cf0e9 199 * If ECDSA should not be supported, set this pointer to NULL.
ashleymills 0:ff9ebe0cf0e9 200 *
ashleymills 0:ff9ebe0cf0e9 201 * Implement this if you want to verify the other peers public key.
ashleymills 0:ff9ebe0cf0e9 202 * This is mandatory for a DTLS client doing based ECDSA
ashleymills 0:ff9ebe0cf0e9 203 * authentication. A server implementing this will request the
ashleymills 0:ff9ebe0cf0e9 204 * client to do DTLS client authentication.
ashleymills 0:ff9ebe0cf0e9 205 *
ashleymills 0:ff9ebe0cf0e9 206 * @param ctx The current dtls context.
ashleymills 0:ff9ebe0cf0e9 207 * @param session The session where the key will be used.
ashleymills 0:ff9ebe0cf0e9 208 * @param other_pub_x x component of the public key.
ashleymills 0:ff9ebe0cf0e9 209 * @param other_pub_y y component of the public key.
ashleymills 0:ff9ebe0cf0e9 210 * @return @c 0 if public key matches, or less than zero on error.
ashleymills 0:ff9ebe0cf0e9 211 * error codes:
ashleymills 0:ff9ebe0cf0e9 212 * return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE);
ashleymills 0:ff9ebe0cf0e9 213 * return dtls_alert_fatal_create(DTLS_ALERT_UNSUPPORTED_CERTIFICATE);
ashleymills 0:ff9ebe0cf0e9 214 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_REVOKED);
ashleymills 0:ff9ebe0cf0e9 215 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_EXPIRED);
ashleymills 0:ff9ebe0cf0e9 216 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_UNKNOWN);
ashleymills 0:ff9ebe0cf0e9 217 * return dtls_alert_fatal_create(DTLS_ALERT_UNKNOWN_CA);
ashleymills 0:ff9ebe0cf0e9 218 */
ashleymills 0:ff9ebe0cf0e9 219 int (*verify_ecdsa_key)(struct dtls_context_t *ctx,
ashleymills 0:ff9ebe0cf0e9 220 const session_t *session,
ashleymills 0:ff9ebe0cf0e9 221 const unsigned char *other_pub_x,
ashleymills 0:ff9ebe0cf0e9 222 const unsigned char *other_pub_y,
ashleymills 0:ff9ebe0cf0e9 223 size_t key_size);
ashleymills 0:ff9ebe0cf0e9 224 } dtls_handler_t;
ashleymills 0:ff9ebe0cf0e9 225
ashleymills 0:ff9ebe0cf0e9 226 /** Holds global information of the DTLS engine. */
ashleymills 0:ff9ebe0cf0e9 227 typedef struct dtls_context_t {
ashleymills 0:ff9ebe0cf0e9 228 unsigned char cookie_secret[DTLS_COOKIE_SECRET_LENGTH];
ashleymills 0:ff9ebe0cf0e9 229 clock_time_t cookie_secret_age; /**< the time the secret has been generated */
ashleymills 0:ff9ebe0cf0e9 230
ashleymills 0:ff9ebe0cf0e9 231 #ifndef WITH_CONTIKI
ashleymills 0:ff9ebe0cf0e9 232 dtls_peer_t *peers; /**< peer hash map */
ashleymills 0:ff9ebe0cf0e9 233 #else /* WITH_CONTIKI */
ashleymills 0:ff9ebe0cf0e9 234 LIST_STRUCT(peers);
ashleymills 0:ff9ebe0cf0e9 235
ashleymills 0:ff9ebe0cf0e9 236 struct etimer retransmit_timer; /**< fires when the next packet must be sent */
ashleymills 0:ff9ebe0cf0e9 237 #endif /* WITH_CONTIKI */
ashleymills 0:ff9ebe0cf0e9 238
ashleymills 0:ff9ebe0cf0e9 239 LIST_STRUCT(sendqueue); /**< the packets to send */
ashleymills 0:ff9ebe0cf0e9 240
ashleymills 0:ff9ebe0cf0e9 241 void *app; /**< application-specific data */
ashleymills 0:ff9ebe0cf0e9 242
ashleymills 0:ff9ebe0cf0e9 243 dtls_handler_t *h; /**< callback handlers */
ashleymills 0:ff9ebe0cf0e9 244
ashleymills 0:ff9ebe0cf0e9 245 unsigned char readbuf[DTLS_MAX_BUF];
ashleymills 0:ff9ebe0cf0e9 246 } dtls_context_t;
ashleymills 0:ff9ebe0cf0e9 247
ashleymills 0:ff9ebe0cf0e9 248 /**
ashleymills 0:ff9ebe0cf0e9 249 * This function initializes the tinyDTLS memory management and must
ashleymills 0:ff9ebe0cf0e9 250 * be called first.
ashleymills 0:ff9ebe0cf0e9 251 */
ashleymills 0:ff9ebe0cf0e9 252 void dtls_init();
ashleymills 0:ff9ebe0cf0e9 253
ashleymills 0:ff9ebe0cf0e9 254 /**
ashleymills 0:ff9ebe0cf0e9 255 * Creates a new context object. The storage allocated for the new
ashleymills 0:ff9ebe0cf0e9 256 * object must be released with dtls_free_context(). */
ashleymills 0:ff9ebe0cf0e9 257 dtls_context_t *dtls_new_context(void *app_data);
ashleymills 0:ff9ebe0cf0e9 258
ashleymills 0:ff9ebe0cf0e9 259 /** Releases any storage that has been allocated for \p ctx. */
ashleymills 0:ff9ebe0cf0e9 260 void dtls_free_context(dtls_context_t *ctx);
ashleymills 0:ff9ebe0cf0e9 261
ashleymills 0:ff9ebe0cf0e9 262 #define dtls_set_app_data(CTX,DATA) ((CTX)->app = (DATA))
ashleymills 0:ff9ebe0cf0e9 263 #define dtls_get_app_data(CTX) ((CTX)->app)
ashleymills 0:ff9ebe0cf0e9 264
ashleymills 0:ff9ebe0cf0e9 265 /** Sets the callback handler object for @p ctx to @p h. */
ashleymills 0:ff9ebe0cf0e9 266 static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) {
ashleymills 0:ff9ebe0cf0e9 267 ctx->h = h;
ashleymills 0:ff9ebe0cf0e9 268 }
ashleymills 0:ff9ebe0cf0e9 269
ashleymills 0:ff9ebe0cf0e9 270 /**
ashleymills 0:ff9ebe0cf0e9 271 * Establishes a DTLS channel with the specified remote peer @p dst.
ashleymills 0:ff9ebe0cf0e9 272 * This function returns @c 0 if that channel already exists, a value
ashleymills 0:ff9ebe0cf0e9 273 * greater than zero when a new ClientHello message was sent, and
ashleymills 0:ff9ebe0cf0e9 274 * a value less than zero on error.
ashleymills 0:ff9ebe0cf0e9 275 *
ashleymills 0:ff9ebe0cf0e9 276 * @param ctx The DTLS context to use.
ashleymills 0:ff9ebe0cf0e9 277 * @param dst The remote party to connect to.
ashleymills 0:ff9ebe0cf0e9 278 * @return A value less than zero on error, greater or equal otherwise.
ashleymills 0:ff9ebe0cf0e9 279 */
ashleymills 0:ff9ebe0cf0e9 280 int dtls_connect(dtls_context_t *ctx, const session_t *dst);
ashleymills 0:ff9ebe0cf0e9 281
ashleymills 0:ff9ebe0cf0e9 282 /**
ashleymills 0:ff9ebe0cf0e9 283 * Establishes a DTLS channel with the specified remote peer.
ashleymills 0:ff9ebe0cf0e9 284 * This function returns @c 0 if that channel already exists, a value
ashleymills 0:ff9ebe0cf0e9 285 * greater than zero when a new ClientHello message was sent, and
ashleymills 0:ff9ebe0cf0e9 286 * a value less than zero on error.
ashleymills 0:ff9ebe0cf0e9 287 *
ashleymills 0:ff9ebe0cf0e9 288 * @param ctx The DTLS context to use.
ashleymills 0:ff9ebe0cf0e9 289 * @param peer The peer object that describes the session.
ashleymills 0:ff9ebe0cf0e9 290 * @return A value less than zero on error, greater or equal otherwise.
ashleymills 0:ff9ebe0cf0e9 291 */
ashleymills 0:ff9ebe0cf0e9 292 int dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer);
ashleymills 0:ff9ebe0cf0e9 293
ashleymills 0:ff9ebe0cf0e9 294 /**
ashleymills 0:ff9ebe0cf0e9 295 * Closes the DTLS connection associated with @p remote. This function
ashleymills 0:ff9ebe0cf0e9 296 * returns zero on success, and a value less than zero on error.
ashleymills 0:ff9ebe0cf0e9 297 */
ashleymills 0:ff9ebe0cf0e9 298 int dtls_close(dtls_context_t *ctx, const session_t *remote);
ashleymills 0:ff9ebe0cf0e9 299
ashleymills 0:ff9ebe0cf0e9 300 int dtls_renegotiate(dtls_context_t *ctx, const session_t *dst);
ashleymills 0:ff9ebe0cf0e9 301
ashleymills 0:ff9ebe0cf0e9 302 /**
ashleymills 0:ff9ebe0cf0e9 303 * Writes the application data given in @p buf to the peer specified
ashleymills 0:ff9ebe0cf0e9 304 * by @p session.
ashleymills 0:ff9ebe0cf0e9 305 *
ashleymills 0:ff9ebe0cf0e9 306 * @param ctx The DTLS context to use.
ashleymills 0:ff9ebe0cf0e9 307 * @param session The remote transport address and local interface.
ashleymills 0:ff9ebe0cf0e9 308 * @param buf The data to write.
ashleymills 0:ff9ebe0cf0e9 309 * @param len The actual length of @p data.
ashleymills 0:ff9ebe0cf0e9 310 *
ashleymills 0:ff9ebe0cf0e9 311 * @return The number of bytes written or @c -1 on error.
ashleymills 0:ff9ebe0cf0e9 312 */
ashleymills 0:ff9ebe0cf0e9 313 int dtls_write(struct dtls_context_t *ctx, session_t *session,
ashleymills 0:ff9ebe0cf0e9 314 uint8 *buf, size_t len);
ashleymills 0:ff9ebe0cf0e9 315
ashleymills 0:ff9ebe0cf0e9 316 /**
ashleymills 0:ff9ebe0cf0e9 317 * Checks sendqueue of given DTLS context object for any outstanding
ashleymills 0:ff9ebe0cf0e9 318 * packets to be transmitted.
ashleymills 0:ff9ebe0cf0e9 319 *
ashleymills 0:ff9ebe0cf0e9 320 * @param context The DTLS context object to use.
ashleymills 0:ff9ebe0cf0e9 321 * @param next If not NULL, @p next is filled with the timestamp
ashleymills 0:ff9ebe0cf0e9 322 * of the next scheduled retransmission, or @c 0 when no packets are
ashleymills 0:ff9ebe0cf0e9 323 * waiting.
ashleymills 0:ff9ebe0cf0e9 324 */
ashleymills 0:ff9ebe0cf0e9 325 void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next);
ashleymills 0:ff9ebe0cf0e9 326
ashleymills 0:ff9ebe0cf0e9 327 #define DTLS_COOKIE_LENGTH 16
ashleymills 0:ff9ebe0cf0e9 328
ashleymills 0:ff9ebe0cf0e9 329 #define DTLS_CT_CHANGE_CIPHER_SPEC 20
ashleymills 0:ff9ebe0cf0e9 330 #define DTLS_CT_ALERT 21
ashleymills 0:ff9ebe0cf0e9 331 #define DTLS_CT_HANDSHAKE 22
ashleymills 0:ff9ebe0cf0e9 332 #define DTLS_CT_APPLICATION_DATA 23
ashleymills 0:ff9ebe0cf0e9 333
ashleymills 0:ff9ebe0cf0e9 334 /** Generic header structure of the DTLS record layer. */
ashleymills 0:ff9ebe0cf0e9 335 typedef struct {
ashleymills 0:ff9ebe0cf0e9 336 uint8 content_type; /**< content type of the included message */
ashleymills 0:ff9ebe0cf0e9 337 uint16 version; /**< Protocol version */
ashleymills 0:ff9ebe0cf0e9 338 uint16 epoch; /**< counter for cipher state changes */
ashleymills 0:ff9ebe0cf0e9 339 uint48 sequence_number; /**< sequence number */
ashleymills 0:ff9ebe0cf0e9 340 uint16 length; /**< length of the following fragment */
ashleymills 0:ff9ebe0cf0e9 341 /* fragment */
ashleymills 0:ff9ebe0cf0e9 342 } dtls_record_header_t;
ashleymills 0:ff9ebe0cf0e9 343
ashleymills 0:ff9ebe0cf0e9 344 /* Handshake types */
ashleymills 0:ff9ebe0cf0e9 345
ashleymills 0:ff9ebe0cf0e9 346 #define DTLS_HT_HELLO_REQUEST 0
ashleymills 0:ff9ebe0cf0e9 347 #define DTLS_HT_CLIENT_HELLO 1
ashleymills 0:ff9ebe0cf0e9 348 #define DTLS_HT_SERVER_HELLO 2
ashleymills 0:ff9ebe0cf0e9 349 #define DTLS_HT_HELLO_VERIFY_REQUEST 3
ashleymills 0:ff9ebe0cf0e9 350 #define DTLS_HT_CERTIFICATE 11
ashleymills 0:ff9ebe0cf0e9 351 #define DTLS_HT_SERVER_KEY_EXCHANGE 12
ashleymills 0:ff9ebe0cf0e9 352 #define DTLS_HT_CERTIFICATE_REQUEST 13
ashleymills 0:ff9ebe0cf0e9 353 #define DTLS_HT_SERVER_HELLO_DONE 14
ashleymills 0:ff9ebe0cf0e9 354 #define DTLS_HT_CERTIFICATE_VERIFY 15
ashleymills 0:ff9ebe0cf0e9 355 #define DTLS_HT_CLIENT_KEY_EXCHANGE 16
ashleymills 0:ff9ebe0cf0e9 356 #define DTLS_HT_FINISHED 20
ashleymills 0:ff9ebe0cf0e9 357
ashleymills 0:ff9ebe0cf0e9 358 /** Header structure for the DTLS handshake protocol. */
ashleymills 0:ff9ebe0cf0e9 359 typedef struct {
ashleymills 0:ff9ebe0cf0e9 360 uint8 msg_type; /**< Type of handshake message (one of DTLS_HT_) */
ashleymills 0:ff9ebe0cf0e9 361 uint24 length; /**< length of this message */
ashleymills 0:ff9ebe0cf0e9 362 uint16 message_seq; /**< Message sequence number */
ashleymills 0:ff9ebe0cf0e9 363 uint24 fragment_offset; /**< Fragment offset. */
ashleymills 0:ff9ebe0cf0e9 364 uint24 fragment_length; /**< Fragment length. */
ashleymills 0:ff9ebe0cf0e9 365 /* body */
ashleymills 0:ff9ebe0cf0e9 366 } dtls_handshake_header_t;
ashleymills 0:ff9ebe0cf0e9 367
ashleymills 0:ff9ebe0cf0e9 368 /** Structure of the Client Hello message. */
ashleymills 0:ff9ebe0cf0e9 369 typedef struct {
ashleymills 0:ff9ebe0cf0e9 370 uint16 version; /**< Client version */
ashleymills 0:ff9ebe0cf0e9 371 uint32 gmt_random; /**< GMT time of the random byte creation */
ashleymills 0:ff9ebe0cf0e9 372 unsigned char random[28]; /**< Client random bytes */
ashleymills 0:ff9ebe0cf0e9 373 /* session id (up to 32 bytes) */
ashleymills 0:ff9ebe0cf0e9 374 /* cookie (up to 32 bytes) */
ashleymills 0:ff9ebe0cf0e9 375 /* cipher suite (2 to 2^16 -1 bytes) */
ashleymills 0:ff9ebe0cf0e9 376 /* compression method */
ashleymills 0:ff9ebe0cf0e9 377 } dtls_client_hello_t;
ashleymills 0:ff9ebe0cf0e9 378
ashleymills 0:ff9ebe0cf0e9 379 /** Structure of the Hello Verify Request. */
ashleymills 0:ff9ebe0cf0e9 380 typedef struct {
ashleymills 0:ff9ebe0cf0e9 381 uint16 version; /**< Server version */
ashleymills 0:ff9ebe0cf0e9 382 uint8 cookie_length; /**< Length of the included cookie */
ashleymills 0:ff9ebe0cf0e9 383 uint8 cookie[]; /**< up to 32 bytes making up the cookie */
ashleymills 0:ff9ebe0cf0e9 384 } dtls_hello_verify_t;
ashleymills 0:ff9ebe0cf0e9 385
ashleymills 0:ff9ebe0cf0e9 386 #if 0
ashleymills 0:ff9ebe0cf0e9 387 /**
ashleymills 0:ff9ebe0cf0e9 388 * Checks a received DTLS record for consistency and eventually decrypt,
ashleymills 0:ff9ebe0cf0e9 389 * verify, decompress and reassemble the contained fragment for
ashleymills 0:ff9ebe0cf0e9 390 * delivery to high-lever clients.
ashleymills 0:ff9ebe0cf0e9 391 *
ashleymills 0:ff9ebe0cf0e9 392 * \param state The DTLS record state for the current session.
ashleymills 0:ff9ebe0cf0e9 393 * \param
ashleymills 0:ff9ebe0cf0e9 394 */
ashleymills 0:ff9ebe0cf0e9 395 int dtls_record_read(dtls_state_t *state, uint8 *msg, int msglen);
ashleymills 0:ff9ebe0cf0e9 396 #endif
ashleymills 0:ff9ebe0cf0e9 397
ashleymills 0:ff9ebe0cf0e9 398 /**
ashleymills 0:ff9ebe0cf0e9 399 * Handles incoming data as DTLS message from given peer.
ashleymills 0:ff9ebe0cf0e9 400 *
ashleymills 0:ff9ebe0cf0e9 401 * @param ctx The dtls context to use.
ashleymills 0:ff9ebe0cf0e9 402 * @param session The current session
ashleymills 0:ff9ebe0cf0e9 403 * @param msg The received data
ashleymills 0:ff9ebe0cf0e9 404 * @param msglen The actual length of @p msg.
ashleymills 0:ff9ebe0cf0e9 405 * @return A value less than zero on error, zero on success.
ashleymills 0:ff9ebe0cf0e9 406 */
ashleymills 0:ff9ebe0cf0e9 407 int dtls_handle_message(dtls_context_t *ctx, session_t *session,
ashleymills 0:ff9ebe0cf0e9 408 uint8 *msg, int msglen);
ashleymills 0:ff9ebe0cf0e9 409
ashleymills 0:ff9ebe0cf0e9 410 /**
ashleymills 0:ff9ebe0cf0e9 411 * Check if @p session is associated with a peer object in @p context.
ashleymills 0:ff9ebe0cf0e9 412 * This function returns a pointer to the peer if found, NULL otherwise.
ashleymills 0:ff9ebe0cf0e9 413 *
ashleymills 0:ff9ebe0cf0e9 414 * @param context The DTLS context to search.
ashleymills 0:ff9ebe0cf0e9 415 * @param session The remote address and local interface
ashleymills 0:ff9ebe0cf0e9 416 * @return A pointer to the peer associated with @p session or NULL if
ashleymills 0:ff9ebe0cf0e9 417 * none exists.
ashleymills 0:ff9ebe0cf0e9 418 */
ashleymills 0:ff9ebe0cf0e9 419 dtls_peer_t *dtls_get_peer(const dtls_context_t *context,
ashleymills 0:ff9ebe0cf0e9 420 const session_t *session);
ashleymills 0:ff9ebe0cf0e9 421
ashleymills 0:ff9ebe0cf0e9 422
ashleymills 0:ff9ebe0cf0e9 423 /**
ashleymills 0:ff9ebe0cf0e9 424 * @mainpage
ashleymills 0:ff9ebe0cf0e9 425 *
ashleymills 0:ff9ebe0cf0e9 426 * @author Olaf Bergmann, TZI Uni Bremen
ashleymills 0:ff9ebe0cf0e9 427 *
ashleymills 0:ff9ebe0cf0e9 428 * This library provides a very simple datagram server with DTLS
ashleymills 0:ff9ebe0cf0e9 429 * support. It is designed to support session multiplexing in
ashleymills 0:ff9ebe0cf0e9 430 * single-threaded applications and thus targets specifically on
ashleymills 0:ff9ebe0cf0e9 431 * embedded systems.
ashleymills 0:ff9ebe0cf0e9 432 *
ashleymills 0:ff9ebe0cf0e9 433 * @section license License
ashleymills 0:ff9ebe0cf0e9 434 *
ashleymills 0:ff9ebe0cf0e9 435 * This software is under the <a
ashleymills 0:ff9ebe0cf0e9 436 * href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>.
ashleymills 0:ff9ebe0cf0e9 437 *
ashleymills 0:ff9ebe0cf0e9 438 * @subsection uthash UTHash
ashleymills 0:ff9ebe0cf0e9 439 *
ashleymills 0:ff9ebe0cf0e9 440 * This library uses <a href="http://uthash.sourceforge.net/">uthash</a> to manage
ashleymills 0:ff9ebe0cf0e9 441 * its peers (not used for Contiki). @b uthash uses the <b>BSD revised license</b>, see
ashleymills 0:ff9ebe0cf0e9 442 * <a href="http://uthash.sourceforge.net/license.html">http://uthash.sourceforge.net/license.html</a>.
ashleymills 0:ff9ebe0cf0e9 443 *
ashleymills 0:ff9ebe0cf0e9 444 * @subsection sha256 Aaron D. Gifford's SHA256 Implementation
ashleymills 0:ff9ebe0cf0e9 445 *
ashleymills 0:ff9ebe0cf0e9 446 * tinyDTLS provides HMAC-SHA256 with BSD-licensed code from Aaron D. Gifford,
ashleymills 0:ff9ebe0cf0e9 447 * see <a href="http://www.aarongifford.com/">www.aarongifford.com</a>.
ashleymills 0:ff9ebe0cf0e9 448 *
ashleymills 0:ff9ebe0cf0e9 449 * @subsection aes Rijndael Implementation From OpenBSD
ashleymills 0:ff9ebe0cf0e9 450 *
ashleymills 0:ff9ebe0cf0e9 451 * The AES implementation is taken from rijndael.{c,h} contained in the crypto
ashleymills 0:ff9ebe0cf0e9 452 * sub-system of the OpenBSD operating system. It is copyright by Vincent Rijmen, *
ashleymills 0:ff9ebe0cf0e9 453 * Antoon Bosselaers and Paulo Barreto. See <a
ashleymills 0:ff9ebe0cf0e9 454 * href="http://www.openbsd.org/cgi-bin/cvsweb/src/sys/crypto/rijndael.c">rijndael.c</a>
ashleymills 0:ff9ebe0cf0e9 455 * for License info.
ashleymills 0:ff9ebe0cf0e9 456 *
ashleymills 0:ff9ebe0cf0e9 457 * @section download Getting the Files
ashleymills 0:ff9ebe0cf0e9 458 *
ashleymills 0:ff9ebe0cf0e9 459 * You can get the sources either from the <a
ashleymills 0:ff9ebe0cf0e9 460 * href="http://sourceforge.net/projects/tinydtls/files">downloads</a> section or
ashleymills 0:ff9ebe0cf0e9 461 * through git from the <a
ashleymills 0:ff9ebe0cf0e9 462 * href="http://sourceforge.net/projects/tinydtls/develop">project develop page</a>.
ashleymills 0:ff9ebe0cf0e9 463 *
ashleymills 0:ff9ebe0cf0e9 464 * @section config Configuration
ashleymills 0:ff9ebe0cf0e9 465 *
ashleymills 0:ff9ebe0cf0e9 466 * Use @c configure to set up everything for a successful build. For Contiki, use the
ashleymills 0:ff9ebe0cf0e9 467 * option @c --with-contiki.
ashleymills 0:ff9ebe0cf0e9 468 *
ashleymills 0:ff9ebe0cf0e9 469 * @section build Building
ashleymills 0:ff9ebe0cf0e9 470 *
ashleymills 0:ff9ebe0cf0e9 471 * After configuration, just type
ashleymills 0:ff9ebe0cf0e9 472 * @code
ashleymills 0:ff9ebe0cf0e9 473 make
ashleymills 0:ff9ebe0cf0e9 474 * @endcode
ashleymills 0:ff9ebe0cf0e9 475 * optionally followed by
ashleymills 0:ff9ebe0cf0e9 476 * @code
ashleymills 0:ff9ebe0cf0e9 477 make install
ashleymills 0:ff9ebe0cf0e9 478 * @endcode
ashleymills 0:ff9ebe0cf0e9 479 * The Contiki version is integrated with the Contiki build system, hence you do not
ashleymills 0:ff9ebe0cf0e9 480 * need to invoke @c make explicitely. Just add @c tinydtls to the variable @c APPS
ashleymills 0:ff9ebe0cf0e9 481 * in your @c Makefile.
ashleymills 0:ff9ebe0cf0e9 482 *
ashleymills 0:ff9ebe0cf0e9 483 * @addtogroup dtls_usage DTLS Usage
ashleymills 0:ff9ebe0cf0e9 484 *
ashleymills 0:ff9ebe0cf0e9 485 * @section dtls_server_example DTLS Server Example
ashleymills 0:ff9ebe0cf0e9 486 *
ashleymills 0:ff9ebe0cf0e9 487 * This section shows how to use the DTLS library functions to setup a
ashleymills 0:ff9ebe0cf0e9 488 * simple secure UDP echo server. The application is responsible for the
ashleymills 0:ff9ebe0cf0e9 489 * entire network communication and thus will look like a usual UDP
ashleymills 0:ff9ebe0cf0e9 490 * server with socket creation and binding and a typical select-loop as
ashleymills 0:ff9ebe0cf0e9 491 * shown below. The minimum configuration required for DTLS is the
ashleymills 0:ff9ebe0cf0e9 492 * creation of the dtls_context_t using dtls_new_context(), and a callback
ashleymills 0:ff9ebe0cf0e9 493 * for sending data. Received packets are read by the application and
ashleymills 0:ff9ebe0cf0e9 494 * passed to dtls_handle_message() as shown in @ref dtls_read_cb.
ashleymills 0:ff9ebe0cf0e9 495 * For any useful communication to happen, read and write call backs
ashleymills 0:ff9ebe0cf0e9 496 * and a key management function should be registered as well.
ashleymills 0:ff9ebe0cf0e9 497 *
ashleymills 0:ff9ebe0cf0e9 498 * @code
ashleymills 0:ff9ebe0cf0e9 499 dtls_context_t *the_context = NULL;
ashleymills 0:ff9ebe0cf0e9 500 int fd, result;
ashleymills 0:ff9ebe0cf0e9 501
ashleymills 0:ff9ebe0cf0e9 502 static dtls_handler_t cb = {
ashleymills 0:ff9ebe0cf0e9 503 .write = send_to_peer,
ashleymills 0:ff9ebe0cf0e9 504 .read = read_from_peer,
ashleymills 0:ff9ebe0cf0e9 505 .event = NULL,
ashleymills 0:ff9ebe0cf0e9 506 .get_psk_key = get_psk_key
ashleymills 0:ff9ebe0cf0e9 507 };
ashleymills 0:ff9ebe0cf0e9 508
ashleymills 0:ff9ebe0cf0e9 509 fd = socket(...);
ashleymills 0:ff9ebe0cf0e9 510 if (fd < 0 || bind(fd, ...) < 0)
ashleymills 0:ff9ebe0cf0e9 511 exit(-1);
ashleymills 0:ff9ebe0cf0e9 512
ashleymills 0:ff9ebe0cf0e9 513 the_context = dtls_new_context(&fd);
ashleymills 0:ff9ebe0cf0e9 514 dtls_set_handler(the_context, &cb);
ashleymills 0:ff9ebe0cf0e9 515
ashleymills 0:ff9ebe0cf0e9 516 while (1) {
ashleymills 0:ff9ebe0cf0e9 517 ...initialize fd_set rfds and timeout ...
ashleymills 0:ff9ebe0cf0e9 518 result = select(fd+1, &rfds, NULL, 0, NULL);
ashleymills 0:ff9ebe0cf0e9 519
ashleymills 0:ff9ebe0cf0e9 520 if (FD_ISSET(fd, &rfds))
ashleymills 0:ff9ebe0cf0e9 521 dtls_handle_read(the_context);
ashleymills 0:ff9ebe0cf0e9 522 }
ashleymills 0:ff9ebe0cf0e9 523
ashleymills 0:ff9ebe0cf0e9 524 dtls_free_context(the_context);
ashleymills 0:ff9ebe0cf0e9 525 * @endcode
ashleymills 0:ff9ebe0cf0e9 526 *
ashleymills 0:ff9ebe0cf0e9 527 * @subsection dtls_read_cb The Read Callback
ashleymills 0:ff9ebe0cf0e9 528 *
ashleymills 0:ff9ebe0cf0e9 529 * The DTLS library expects received raw data to be passed to
ashleymills 0:ff9ebe0cf0e9 530 * dtls_handle_message(). The application is responsible for
ashleymills 0:ff9ebe0cf0e9 531 * filling a session_t structure with the address data of the
ashleymills 0:ff9ebe0cf0e9 532 * remote peer as illustrated by the following example:
ashleymills 0:ff9ebe0cf0e9 533 *
ashleymills 0:ff9ebe0cf0e9 534 * @code
ashleymills 0:ff9ebe0cf0e9 535 int dtls_handle_read(struct dtls_context_t *ctx) {
ashleymills 0:ff9ebe0cf0e9 536 int *fd;
ashleymills 0:ff9ebe0cf0e9 537 session_t session;
ashleymills 0:ff9ebe0cf0e9 538 static uint8 buf[DTLS_MAX_BUF];
ashleymills 0:ff9ebe0cf0e9 539 int len;
ashleymills 0:ff9ebe0cf0e9 540
ashleymills 0:ff9ebe0cf0e9 541 fd = dtls_get_app_data(ctx);
ashleymills 0:ff9ebe0cf0e9 542
ashleymills 0:ff9ebe0cf0e9 543 assert(fd);
ashleymills 0:ff9ebe0cf0e9 544
ashleymills 0:ff9ebe0cf0e9 545 session.size = sizeof(session.addr);
ashleymills 0:ff9ebe0cf0e9 546 len = recvfrom(*fd, buf, sizeof(buf), 0, &session.addr.sa, &session.size);
ashleymills 0:ff9ebe0cf0e9 547
ashleymills 0:ff9ebe0cf0e9 548 return len < 0 ? len : dtls_handle_message(ctx, &session, buf, len);
ashleymills 0:ff9ebe0cf0e9 549 }
ashleymills 0:ff9ebe0cf0e9 550 * @endcode
ashleymills 0:ff9ebe0cf0e9 551 *
ashleymills 0:ff9ebe0cf0e9 552 * Once a new DTLS session was established and DTLS ApplicationData has been
ashleymills 0:ff9ebe0cf0e9 553 * received, the DTLS server invokes the read callback with the MAC-verified
ashleymills 0:ff9ebe0cf0e9 554 * cleartext data as its argument. A read callback for a simple echo server
ashleymills 0:ff9ebe0cf0e9 555 * could look like this:
ashleymills 0:ff9ebe0cf0e9 556 * @code
ashleymills 0:ff9ebe0cf0e9 557 int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
ashleymills 0:ff9ebe0cf0e9 558 return dtls_write(ctx, session, data, len);
ashleymills 0:ff9ebe0cf0e9 559 }
ashleymills 0:ff9ebe0cf0e9 560 * @endcode
ashleymills 0:ff9ebe0cf0e9 561 *
ashleymills 0:ff9ebe0cf0e9 562 * @subsection dtls_send_cb The Send Callback
ashleymills 0:ff9ebe0cf0e9 563 *
ashleymills 0:ff9ebe0cf0e9 564 * The callback function send_to_peer() is called whenever data must be
ashleymills 0:ff9ebe0cf0e9 565 * sent over the network. Here, the sendto() system call is used to
ashleymills 0:ff9ebe0cf0e9 566 * transmit data within the given session. The socket descriptor required
ashleymills 0:ff9ebe0cf0e9 567 * by sendto() has been registered as application data when the DTLS context
ashleymills 0:ff9ebe0cf0e9 568 * was created with dtls_new_context().
ashleymills 0:ff9ebe0cf0e9 569 * Note that it is on the application to buffer the data when it cannot be
ashleymills 0:ff9ebe0cf0e9 570 * sent at the time this callback is invoked. The following example thus
ashleymills 0:ff9ebe0cf0e9 571 * is incomplete as it would have to deal with EAGAIN somehow.
ashleymills 0:ff9ebe0cf0e9 572 * @code
ashleymills 0:ff9ebe0cf0e9 573 int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
ashleymills 0:ff9ebe0cf0e9 574 int fd = *(int *)dtls_get_app_data(ctx);
ashleymills 0:ff9ebe0cf0e9 575 return sendto(fd, data, len, MSG_DONTWAIT, &session->addr.sa, session->size);
ashleymills 0:ff9ebe0cf0e9 576 }
ashleymills 0:ff9ebe0cf0e9 577 * @endcode
ashleymills 0:ff9ebe0cf0e9 578 *
ashleymills 0:ff9ebe0cf0e9 579 * @subsection dtls_get_psk_key The Key Storage
ashleymills 0:ff9ebe0cf0e9 580 *
ashleymills 0:ff9ebe0cf0e9 581 * When a new DTLS session is created, the library must ask the application
ashleymills 0:ff9ebe0cf0e9 582 * for keying material. To do so, it invokes the registered call-back function
ashleymills 0:ff9ebe0cf0e9 583 * get_psk_key() with the current context and session information as parameter.
ashleymills 0:ff9ebe0cf0e9 584 * When the function is called with the @p id parameter set, the result must
ashleymills 0:ff9ebe0cf0e9 585 * point to a dtls_psk_key_t structure for the given identity. When @p id is
ashleymills 0:ff9ebe0cf0e9 586 * @c NULL, the function must pick a suitable identity and return a pointer to
ashleymills 0:ff9ebe0cf0e9 587 * the corresponding dtls_psk_key_t structure. The following example shows a
ashleymills 0:ff9ebe0cf0e9 588 * simple key storage for a pre-shared key for @c Client_identity:
ashleymills 0:ff9ebe0cf0e9 589 *
ashleymills 0:ff9ebe0cf0e9 590 * @code
ashleymills 0:ff9ebe0cf0e9 591 int get_psk_key(struct dtls_context_t *ctx,
ashleymills 0:ff9ebe0cf0e9 592 const session_t *session,
ashleymills 0:ff9ebe0cf0e9 593 const unsigned char *id, size_t id_len,
ashleymills 0:ff9ebe0cf0e9 594 const dtls_psk_key_t **result) {
ashleymills 0:ff9ebe0cf0e9 595
ashleymills 0:ff9ebe0cf0e9 596 static const dtls_psk_key_t psk = {
ashleymills 0:ff9ebe0cf0e9 597 .id = (unsigned char *)"my identity",
ashleymills 0:ff9ebe0cf0e9 598 .id_length = 11,
ashleymills 0:ff9ebe0cf0e9 599 .key = (unsigned char *)"secret",
ashleymills 0:ff9ebe0cf0e9 600 .key_length = 6
ashleymills 0:ff9ebe0cf0e9 601 };
ashleymills 0:ff9ebe0cf0e9 602
ashleymills 0:ff9ebe0cf0e9 603 *result = &psk;
ashleymills 0:ff9ebe0cf0e9 604 return 0;
ashleymills 0:ff9ebe0cf0e9 605 }
ashleymills 0:ff9ebe0cf0e9 606 * @endcode
ashleymills 0:ff9ebe0cf0e9 607 *
ashleymills 0:ff9ebe0cf0e9 608 * @subsection dtls_events The Event Notifier
ashleymills 0:ff9ebe0cf0e9 609 *
ashleymills 0:ff9ebe0cf0e9 610 * Applications that want to be notified whenever the status of a DTLS session
ashleymills 0:ff9ebe0cf0e9 611 * has changed can register an event handling function with the field @c event
ashleymills 0:ff9ebe0cf0e9 612 * in the dtls_handler_t structure (see \ref dtls_server_example). The call-back
ashleymills 0:ff9ebe0cf0e9 613 * function is called for alert messages and internal state changes. For alert
ashleymills 0:ff9ebe0cf0e9 614 * messages, the argument @p level will be set to a value greate than zero, and
ashleymills 0:ff9ebe0cf0e9 615 * @p code will indicate the notification code. For internal events, @p level
ashleymills 0:ff9ebe0cf0e9 616 * is @c 0, and @p code a value greater than @c 255.
ashleymills 0:ff9ebe0cf0e9 617 *
ashleymills 0:ff9ebe0cf0e9 618 * Currently, the only defined internal event is @c DTLS_EVENT_CONNECTED. It
ashleymills 0:ff9ebe0cf0e9 619 * indicates successful establishment of a new DTLS channel.
ashleymills 0:ff9ebe0cf0e9 620 *
ashleymills 0:ff9ebe0cf0e9 621 * @code
ashleymills 0:ff9ebe0cf0e9 622 int handle_event(struct dtls_context_t *ctx, session_t *session,
ashleymills 0:ff9ebe0cf0e9 623 dtls_alert_level_t level, unsigned short code) {
ashleymills 0:ff9ebe0cf0e9 624 ... do something with event ...
ashleymills 0:ff9ebe0cf0e9 625 return 0;
ashleymills 0:ff9ebe0cf0e9 626 }
ashleymills 0:ff9ebe0cf0e9 627 * @endcode
ashleymills 0:ff9ebe0cf0e9 628 *
ashleymills 0:ff9ebe0cf0e9 629 * @section dtls_client_example DTLS Client Example
ashleymills 0:ff9ebe0cf0e9 630 *
ashleymills 0:ff9ebe0cf0e9 631 * A DTLS client is constructed like a server but needs to actively setup
ashleymills 0:ff9ebe0cf0e9 632 * a new session by calling dtls_connect() at some point. As this function
ashleymills 0:ff9ebe0cf0e9 633 * usually returns before the new DTLS channel is established, the application
ashleymills 0:ff9ebe0cf0e9 634 * must register an event handler and wait for @c DTLS_EVENT_CONNECT before
ashleymills 0:ff9ebe0cf0e9 635 * it can send data over the DTLS channel.
ashleymills 0:ff9ebe0cf0e9 636 *
ashleymills 0:ff9ebe0cf0e9 637 */
ashleymills 0:ff9ebe0cf0e9 638
ashleymills 0:ff9ebe0cf0e9 639 /**
ashleymills 0:ff9ebe0cf0e9 640 * @addtogroup contiki Contiki
ashleymills 0:ff9ebe0cf0e9 641 *
ashleymills 0:ff9ebe0cf0e9 642 * To use tinyDTLS as Contiki application, place the source code in the directory
ashleymills 0:ff9ebe0cf0e9 643 * @c apps/tinydtls in the Contiki source tree and invoke configure with the option
ashleymills 0:ff9ebe0cf0e9 644 * @c --with-contiki. This will create the tinydtls Makefile and config.h from the
ashleymills 0:ff9ebe0cf0e9 645 * templates @c Makefile.contiki and @c config.h.contiki instead of the usual
ashleymills 0:ff9ebe0cf0e9 646 * templates ending in @c .in.
ashleymills 0:ff9ebe0cf0e9 647 *
ashleymills 0:ff9ebe0cf0e9 648 * Then, create a Contiki project with @c APPS += tinydtls in its Makefile. A sample
ashleymills 0:ff9ebe0cf0e9 649 * server could look like this (with read_from_peer() and get_psk_key() as shown above).
ashleymills 0:ff9ebe0cf0e9 650 *
ashleymills 0:ff9ebe0cf0e9 651 * @code
ashleymills 0:ff9ebe0cf0e9 652 #include "contiki.h"
ashleymills 0:ff9ebe0cf0e9 653
ashleymills 0:ff9ebe0cf0e9 654 #include "config.h"
ashleymills 0:ff9ebe0cf0e9 655 #include "dtls.h"
ashleymills 0:ff9ebe0cf0e9 656
ashleymills 0:ff9ebe0cf0e9 657 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
ashleymills 0:ff9ebe0cf0e9 658 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
ashleymills 0:ff9ebe0cf0e9 659
ashleymills 0:ff9ebe0cf0e9 660 int send_to_peer(struct dtls_context_t *, session_t *, uint8 *, size_t);
ashleymills 0:ff9ebe0cf0e9 661
ashleymills 0:ff9ebe0cf0e9 662 static struct uip_udp_conn *server_conn;
ashleymills 0:ff9ebe0cf0e9 663 static dtls_context_t *dtls_context;
ashleymills 0:ff9ebe0cf0e9 664
ashleymills 0:ff9ebe0cf0e9 665 static dtls_handler_t cb = {
ashleymills 0:ff9ebe0cf0e9 666 .write = send_to_peer,
ashleymills 0:ff9ebe0cf0e9 667 .read = read_from_peer,
ashleymills 0:ff9ebe0cf0e9 668 .event = NULL,
ashleymills 0:ff9ebe0cf0e9 669 .get_psk_key = get_psk_key
ashleymills 0:ff9ebe0cf0e9 670 };
ashleymills 0:ff9ebe0cf0e9 671
ashleymills 0:ff9ebe0cf0e9 672 PROCESS(server_process, "DTLS server process");
ashleymills 0:ff9ebe0cf0e9 673 AUTOSTART_PROCESSES(&server_process);
ashleymills 0:ff9ebe0cf0e9 674
ashleymills 0:ff9ebe0cf0e9 675 PROCESS_THREAD(server_process, ev, data)
ashleymills 0:ff9ebe0cf0e9 676 {
ashleymills 0:ff9ebe0cf0e9 677 PROCESS_BEGIN();
ashleymills 0:ff9ebe0cf0e9 678
ashleymills 0:ff9ebe0cf0e9 679 dtls_init();
ashleymills 0:ff9ebe0cf0e9 680
ashleymills 0:ff9ebe0cf0e9 681 server_conn = udp_new(NULL, 0, NULL);
ashleymills 0:ff9ebe0cf0e9 682 udp_bind(server_conn, UIP_HTONS(5684));
ashleymills 0:ff9ebe0cf0e9 683
ashleymills 0:ff9ebe0cf0e9 684 dtls_context = dtls_new_context(server_conn);
ashleymills 0:ff9ebe0cf0e9 685 if (!dtls_context) {
ashleymills 0:ff9ebe0cf0e9 686 dsrv_log(LOG_EMERG, "cannot create context\n");
ashleymills 0:ff9ebe0cf0e9 687 PROCESS_EXIT();
ashleymills 0:ff9ebe0cf0e9 688 }
ashleymills 0:ff9ebe0cf0e9 689
ashleymills 0:ff9ebe0cf0e9 690 dtls_set_handler(dtls_context, &cb);
ashleymills 0:ff9ebe0cf0e9 691
ashleymills 0:ff9ebe0cf0e9 692 while(1) {
ashleymills 0:ff9ebe0cf0e9 693 PROCESS_WAIT_EVENT();
ashleymills 0:ff9ebe0cf0e9 694 if(ev == tcpip_event && uip_newdata()) {
ashleymills 0:ff9ebe0cf0e9 695 session_t session;
ashleymills 0:ff9ebe0cf0e9 696
ashleymills 0:ff9ebe0cf0e9 697 uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
ashleymills 0:ff9ebe0cf0e9 698 session.port = UIP_UDP_BUF->srcport;
ashleymills 0:ff9ebe0cf0e9 699 session.size = sizeof(session.addr) + sizeof(session.port);
ashleymills 0:ff9ebe0cf0e9 700
ashleymills 0:ff9ebe0cf0e9 701 dtls_handle_message(ctx, &session, uip_appdata, uip_datalen());
ashleymills 0:ff9ebe0cf0e9 702 }
ashleymills 0:ff9ebe0cf0e9 703 }
ashleymills 0:ff9ebe0cf0e9 704
ashleymills 0:ff9ebe0cf0e9 705 PROCESS_END();
ashleymills 0:ff9ebe0cf0e9 706 }
ashleymills 0:ff9ebe0cf0e9 707
ashleymills 0:ff9ebe0cf0e9 708 int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
ashleymills 0:ff9ebe0cf0e9 709 struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
ashleymills 0:ff9ebe0cf0e9 710
ashleymills 0:ff9ebe0cf0e9 711 uip_ipaddr_copy(&conn->ripaddr, &session->addr);
ashleymills 0:ff9ebe0cf0e9 712 conn->rport = session->port;
ashleymills 0:ff9ebe0cf0e9 713
ashleymills 0:ff9ebe0cf0e9 714 uip_udp_packet_send(conn, data, len);
ashleymills 0:ff9ebe0cf0e9 715
ashleymills 0:ff9ebe0cf0e9 716 memset(&conn->ripaddr, 0, sizeof(server_conn->ripaddr));
ashleymills 0:ff9ebe0cf0e9 717 memset(&conn->rport, 0, sizeof(conn->rport));
ashleymills 0:ff9ebe0cf0e9 718
ashleymills 0:ff9ebe0cf0e9 719 return len;
ashleymills 0:ff9ebe0cf0e9 720 }
ashleymills 0:ff9ebe0cf0e9 721 * @endcode
ashleymills 0:ff9ebe0cf0e9 722 */
ashleymills 0:ff9ebe0cf0e9 723
ashleymills 0:ff9ebe0cf0e9 724 #ifdef __cplusplus
ashleymills 0:ff9ebe0cf0e9 725 }
ashleymills 1:598a56fe116e 726 #endif
ashleymills 1:598a56fe116e 727
ashleymills 1:598a56fe116e 728 #endif /* _DTLS_H_ */