Version 0.5.0 of tinydtls
Dependents: tinydtls_test_cellular tinydtls_test_ethernet tiny-dtls
dtls.h@1:598a56fe116e, 2014-02-12 (annotated)
- 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?
User | Revision | Line number | New 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_ */ |