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