Version 0.5.0 of tinydtls
Dependents: tinydtls_test_cellular tinydtls_test_ethernet tiny-dtls
dtls.h
00001 /* dtls -- a very basic DTLS implementation 00002 * 00003 * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org> 00004 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de> 00005 * 00006 * Permission is hereby granted, free of charge, to any person 00007 * obtaining a copy of this software and associated documentation 00008 * files (the "Software"), to deal in the Software without 00009 * restriction, including without limitation the rights to use, copy, 00010 * modify, merge, publish, distribute, sublicense, and/or sell copies 00011 * of the Software, and to permit persons to whom the Software is 00012 * furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be 00015 * included in all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00018 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00020 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00021 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00022 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00023 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00024 * SOFTWARE. 00025 */ 00026 00027 /** 00028 * @file dtls.h 00029 * @brief High level DTLS API and visible structures. 00030 */ 00031 00032 #ifndef _DTLS_H_ 00033 #define _DTLS_H_ 00034 00035 #include <stdint.h> 00036 00037 #define MBED 00038 00039 #include "t_list.h" 00040 #include "state.h" 00041 #include "peer.h" 00042 00043 #ifndef WITH_CONTIKI 00044 #include "uthash.h" 00045 #include "t_list.h" 00046 #endif /* WITH_CONTIKI */ 00047 00048 #include "alert.h" 00049 #include "crypto.h" 00050 #include "hmac.h" 00051 00052 #include "global.h" 00053 #include "dtls_time.h" 00054 00055 #ifndef DTLSv12 00056 #define DTLS_VERSION 0xfeff /* DTLS v1.1 */ 00057 #else 00058 #define DTLS_VERSION 0xfefd /* DTLS v1.2 */ 00059 #endif 00060 00061 00062 00063 /* This is the maximal supported length of the psk client identity and psk 00064 * server identity hint */ 00065 #define DTLS_PSK_MAX_CLIENT_IDENTITY_LEN 32 00066 00067 typedef struct dtls_psk_key_t { 00068 unsigned char *id; /**< psk identity */ 00069 size_t id_length; /**< length of psk identity */ 00070 unsigned char *key; /**< key data */ 00071 size_t key_length; /**< length of key */ 00072 } dtls_psk_key_t; 00073 00074 typedef struct dtls_ecdsa_key_t { 00075 dtls_ecdh_curve curve; 00076 const unsigned char *priv_key; /** < private key as bytes > */ 00077 const unsigned char *pub_key_x; /** < x part of the public key for the given private key > */ 00078 const unsigned char *pub_key_y; /** < y part of the public key for the given private key > */ 00079 } dtls_ecdsa_key_t; 00080 00081 /** Length of the secret that is used for generating Hello Verify cookies. */ 00082 #define DTLS_COOKIE_SECRET_LENGTH 12 00083 00084 struct dtls_context_t; 00085 00086 #ifdef __cplusplus 00087 extern "C" { 00088 #endif 00089 00090 /** 00091 * This structure contains callback functions used by tinydtls to 00092 * communicate with the application. At least the write function must 00093 * be provided. It is called by the DTLS state machine to send packets 00094 * over the network. The read function is invoked to deliver decrypted 00095 * and verfified application data. The third callback is an event 00096 * handler function that is called when alert messages are encountered 00097 * or events generated by the library have occured. 00098 */ 00099 typedef struct { 00100 /** 00101 * Called from dtls_handle_message() to send DTLS packets over the 00102 * network. The callback function must use the network interface 00103 * denoted by session->ifindex to send the data. 00104 * 00105 * @param ctx The current DTLS context. 00106 * @param session The session object, including the address of the 00107 * remote peer where the data shall be sent. 00108 * @param buf The data to send. 00109 * @param len The actual length of @p buf. 00110 * @return The callback function must return the number of bytes 00111 * that were sent, or a value less than zero to indicate an 00112 * error. 00113 */ 00114 int (*write)(struct dtls_context_t *ctx, 00115 session_t *session, uint8 *buf, size_t len); 00116 00117 /** 00118 * Called from dtls_handle_message() deliver application data that was 00119 * received on the given session. The data is delivered only after 00120 * decryption and verification have succeeded. 00121 * 00122 * @param ctx The current DTLS context. 00123 * @param session The session object, including the address of the 00124 * data's origin. 00125 * @param buf The received data packet. 00126 * @param len The actual length of @p buf. 00127 * @return ignored 00128 */ 00129 int (*read)(struct dtls_context_t *ctx, 00130 session_t *session, uint8 *buf, size_t len); 00131 00132 /** 00133 * The event handler is called when a message from the alert 00134 * protocol is received or the state of the DTLS session changes. 00135 * 00136 * @param ctx The current dtls context. 00137 * @param session The session object that was affected. 00138 * @param level The alert level or @c 0 when an event ocurred that 00139 * is not an alert. 00140 * @param code Values less than @c 256 indicate alerts, while 00141 * @c 256 or greater indicate internal DTLS session changes. 00142 * @return ignored 00143 */ 00144 int (*event)(struct dtls_context_t *ctx, session_t *session, 00145 dtls_alert_level_t level, unsigned short code); 00146 00147 /** 00148 * Called during handshake to lookup the key for @p id in @p 00149 * session. If found, the key must be stored in @p result and 00150 * the return value must be @c 0. If not found, @p result is 00151 * undefined and the return value must be less than zero. 00152 * If PSK should not be supported, set this pointer to NULL. 00153 * 00154 * @param ctx The current dtls context. 00155 * @param session The session where the key will be used. 00156 * @param id The identity of the communicating peer. This value is 00157 * @c NULL when the DTLS engine requests the local 00158 * id/key pair to use for session setup. 00159 * @param id_len The actual length of @p id 00160 * @param result Must be set to the key object to use.for the given 00161 * session. 00162 * @return @c 0 if result is set, or less than zero on error. 00163 */ 00164 int (*get_psk_key)(struct dtls_context_t *ctx, 00165 const session_t *session, 00166 const unsigned char *id, size_t id_len, 00167 const dtls_psk_key_t **result); 00168 00169 /** 00170 * Called during handshake to get the server's or client's ecdsa 00171 * key used to authenticate this server or client in this 00172 * session. If found, the key must be stored in @p result and 00173 * the return value must be @c 0. If not found, @p result is 00174 * undefined and the return value must be less than zero. 00175 * 00176 * If ECDSA should not be supported, set this pointer to NULL. 00177 * 00178 * Implement this if you want to provide your own certificate to 00179 * the other peer. This is mandatory for a server providing ECDSA 00180 * support and optional for a client. A client doing DTLS client 00181 * authentication has to implementing this callback. 00182 * 00183 * @param ctx The current dtls context. 00184 * @param session The session where the key will be used. 00185 * @param result Must be set to the key object to used for the given 00186 * session. 00187 * @return @c 0 if result is set, or less than zero on error. 00188 */ 00189 int (*get_ecdsa_key)(struct dtls_context_t *ctx, 00190 const session_t *session, 00191 const dtls_ecdsa_key_t **result); 00192 00193 /** 00194 * Called during handshake to check the peer's pubic key in this 00195 * session. If the public key matches the session and should be 00196 * considerated valid the return value must be @c 0. If not valid, 00197 * the return value must be less than zero. 00198 * 00199 * If ECDSA should not be supported, set this pointer to NULL. 00200 * 00201 * Implement this if you want to verify the other peers public key. 00202 * This is mandatory for a DTLS client doing based ECDSA 00203 * authentication. A server implementing this will request the 00204 * client to do DTLS client authentication. 00205 * 00206 * @param ctx The current dtls context. 00207 * @param session The session where the key will be used. 00208 * @param other_pub_x x component of the public key. 00209 * @param other_pub_y y component of the public key. 00210 * @return @c 0 if public key matches, or less than zero on error. 00211 * error codes: 00212 * return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE); 00213 * return dtls_alert_fatal_create(DTLS_ALERT_UNSUPPORTED_CERTIFICATE); 00214 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_REVOKED); 00215 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_EXPIRED); 00216 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_UNKNOWN); 00217 * return dtls_alert_fatal_create(DTLS_ALERT_UNKNOWN_CA); 00218 */ 00219 int (*verify_ecdsa_key)(struct dtls_context_t *ctx, 00220 const session_t *session, 00221 const unsigned char *other_pub_x, 00222 const unsigned char *other_pub_y, 00223 size_t key_size); 00224 } dtls_handler_t; 00225 00226 /** Holds global information of the DTLS engine. */ 00227 typedef struct dtls_context_t { 00228 unsigned char cookie_secret[DTLS_COOKIE_SECRET_LENGTH]; 00229 clock_time_t cookie_secret_age; /**< the time the secret has been generated */ 00230 00231 #ifndef WITH_CONTIKI 00232 dtls_peer_t *peers; /**< peer hash map */ 00233 #else /* WITH_CONTIKI */ 00234 LIST_STRUCT(peers); 00235 00236 struct etimer retransmit_timer; /**< fires when the next packet must be sent */ 00237 #endif /* WITH_CONTIKI */ 00238 00239 LIST_STRUCT(sendqueue); /**< the packets to send */ 00240 00241 void *app; /**< application-specific data */ 00242 00243 dtls_handler_t *h; /**< callback handlers */ 00244 00245 unsigned char readbuf[DTLS_MAX_BUF]; 00246 } dtls_context_t; 00247 00248 /** 00249 * This function initializes the tinyDTLS memory management and must 00250 * be called first. 00251 */ 00252 void dtls_init(); 00253 00254 /** 00255 * Creates a new context object. The storage allocated for the new 00256 * object must be released with dtls_free_context(). */ 00257 dtls_context_t *dtls_new_context(void *app_data); 00258 00259 /** Releases any storage that has been allocated for \p ctx. */ 00260 void dtls_free_context(dtls_context_t *ctx); 00261 00262 #define dtls_set_app_data(CTX,DATA) ((CTX)->app = (DATA)) 00263 #define dtls_get_app_data(CTX) ((CTX)->app) 00264 00265 /** Sets the callback handler object for @p ctx to @p h. */ 00266 static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) { 00267 ctx->h = h; 00268 } 00269 00270 /** 00271 * Establishes a DTLS channel with the specified remote peer @p dst. 00272 * This function returns @c 0 if that channel already exists, a value 00273 * greater than zero when a new ClientHello message was sent, and 00274 * a value less than zero on error. 00275 * 00276 * @param ctx The DTLS context to use. 00277 * @param dst The remote party to connect to. 00278 * @return A value less than zero on error, greater or equal otherwise. 00279 */ 00280 int dtls_connect(dtls_context_t *ctx, const session_t *dst); 00281 00282 /** 00283 * Establishes a DTLS channel with the specified remote peer. 00284 * This function returns @c 0 if that channel already exists, a value 00285 * greater than zero when a new ClientHello message was sent, and 00286 * a value less than zero on error. 00287 * 00288 * @param ctx The DTLS context to use. 00289 * @param peer The peer object that describes the session. 00290 * @return A value less than zero on error, greater or equal otherwise. 00291 */ 00292 int dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer); 00293 00294 /** 00295 * Closes the DTLS connection associated with @p remote. This function 00296 * returns zero on success, and a value less than zero on error. 00297 */ 00298 int dtls_close(dtls_context_t *ctx, const session_t *remote); 00299 00300 int dtls_renegotiate(dtls_context_t *ctx, const session_t *dst); 00301 00302 /** 00303 * Writes the application data given in @p buf to the peer specified 00304 * by @p session. 00305 * 00306 * @param ctx The DTLS context to use. 00307 * @param session The remote transport address and local interface. 00308 * @param buf The data to write. 00309 * @param len The actual length of @p data. 00310 * 00311 * @return The number of bytes written or @c -1 on error. 00312 */ 00313 int dtls_write(struct dtls_context_t *ctx, session_t *session, 00314 uint8 *buf, size_t len); 00315 00316 /** 00317 * Checks sendqueue of given DTLS context object for any outstanding 00318 * packets to be transmitted. 00319 * 00320 * @param context The DTLS context object to use. 00321 * @param next If not NULL, @p next is filled with the timestamp 00322 * of the next scheduled retransmission, or @c 0 when no packets are 00323 * waiting. 00324 */ 00325 void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next); 00326 00327 #define DTLS_COOKIE_LENGTH 16 00328 00329 #define DTLS_CT_CHANGE_CIPHER_SPEC 20 00330 #define DTLS_CT_ALERT 21 00331 #define DTLS_CT_HANDSHAKE 22 00332 #define DTLS_CT_APPLICATION_DATA 23 00333 00334 /** Generic header structure of the DTLS record layer. */ 00335 typedef struct { 00336 uint8 content_type; /**< content type of the included message */ 00337 uint16 version; /**< Protocol version */ 00338 uint16 epoch; /**< counter for cipher state changes */ 00339 uint48 sequence_number; /**< sequence number */ 00340 uint16 length; /**< length of the following fragment */ 00341 /* fragment */ 00342 } dtls_record_header_t; 00343 00344 /* Handshake types */ 00345 00346 #define DTLS_HT_HELLO_REQUEST 0 00347 #define DTLS_HT_CLIENT_HELLO 1 00348 #define DTLS_HT_SERVER_HELLO 2 00349 #define DTLS_HT_HELLO_VERIFY_REQUEST 3 00350 #define DTLS_HT_CERTIFICATE 11 00351 #define DTLS_HT_SERVER_KEY_EXCHANGE 12 00352 #define DTLS_HT_CERTIFICATE_REQUEST 13 00353 #define DTLS_HT_SERVER_HELLO_DONE 14 00354 #define DTLS_HT_CERTIFICATE_VERIFY 15 00355 #define DTLS_HT_CLIENT_KEY_EXCHANGE 16 00356 #define DTLS_HT_FINISHED 20 00357 00358 /** Header structure for the DTLS handshake protocol. */ 00359 typedef struct { 00360 uint8 msg_type; /**< Type of handshake message (one of DTLS_HT_) */ 00361 uint24 length; /**< length of this message */ 00362 uint16 message_seq; /**< Message sequence number */ 00363 uint24 fragment_offset; /**< Fragment offset. */ 00364 uint24 fragment_length; /**< Fragment length. */ 00365 /* body */ 00366 } dtls_handshake_header_t; 00367 00368 /** Structure of the Client Hello message. */ 00369 typedef struct { 00370 uint16 version; /**< Client version */ 00371 uint32 gmt_random; /**< GMT time of the random byte creation */ 00372 unsigned char random[28]; /**< Client random bytes */ 00373 /* session id (up to 32 bytes) */ 00374 /* cookie (up to 32 bytes) */ 00375 /* cipher suite (2 to 2^16 -1 bytes) */ 00376 /* compression method */ 00377 } dtls_client_hello_t; 00378 00379 /** Structure of the Hello Verify Request. */ 00380 typedef struct { 00381 uint16 version; /**< Server version */ 00382 uint8 cookie_length; /**< Length of the included cookie */ 00383 uint8 cookie[]; /**< up to 32 bytes making up the cookie */ 00384 } dtls_hello_verify_t; 00385 00386 #if 0 00387 /** 00388 * Checks a received DTLS record for consistency and eventually decrypt, 00389 * verify, decompress and reassemble the contained fragment for 00390 * delivery to high-lever clients. 00391 * 00392 * \param state The DTLS record state for the current session. 00393 * \param 00394 */ 00395 int dtls_record_read(dtls_state_t *state, uint8 *msg, int msglen); 00396 #endif 00397 00398 /** 00399 * Handles incoming data as DTLS message from given peer. 00400 * 00401 * @param ctx The dtls context to use. 00402 * @param session The current session 00403 * @param msg The received data 00404 * @param msglen The actual length of @p msg. 00405 * @return A value less than zero on error, zero on success. 00406 */ 00407 int dtls_handle_message(dtls_context_t *ctx, session_t *session, 00408 uint8 *msg, int msglen); 00409 00410 /** 00411 * Check if @p session is associated with a peer object in @p context. 00412 * This function returns a pointer to the peer if found, NULL otherwise. 00413 * 00414 * @param context The DTLS context to search. 00415 * @param session The remote address and local interface 00416 * @return A pointer to the peer associated with @p session or NULL if 00417 * none exists. 00418 */ 00419 dtls_peer_t *dtls_get_peer(const dtls_context_t *context, 00420 const session_t *session); 00421 00422 00423 /** 00424 * @mainpage 00425 * 00426 * @author Olaf Bergmann, TZI Uni Bremen 00427 * 00428 * This library provides a very simple datagram server with DTLS 00429 * support. It is designed to support session multiplexing in 00430 * single-threaded applications and thus targets specifically on 00431 * embedded systems. 00432 * 00433 * @section license License 00434 * 00435 * This software is under the <a 00436 * href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>. 00437 * 00438 * @subsection uthash UTHash 00439 * 00440 * This library uses <a href="http://uthash.sourceforge.net/">uthash</a> to manage 00441 * its peers (not used for Contiki). @b uthash uses the <b>BSD revised license</b>, see 00442 * <a href="http://uthash.sourceforge.net/license.html">http://uthash.sourceforge.net/license.html</a>. 00443 * 00444 * @subsection sha256 Aaron D. Gifford's SHA256 Implementation 00445 * 00446 * tinyDTLS provides HMAC-SHA256 with BSD-licensed code from Aaron D. Gifford, 00447 * see <a href="http://www.aarongifford.com/">www.aarongifford.com</a>. 00448 * 00449 * @subsection aes Rijndael Implementation From OpenBSD 00450 * 00451 * The AES implementation is taken from rijndael.{c,h} contained in the crypto 00452 * sub-system of the OpenBSD operating system. It is copyright by Vincent Rijmen, * 00453 * Antoon Bosselaers and Paulo Barreto. See <a 00454 * href="http://www.openbsd.org/cgi-bin/cvsweb/src/sys/crypto/rijndael.c">rijndael.c</a> 00455 * for License info. 00456 * 00457 * @section download Getting the Files 00458 * 00459 * You can get the sources either from the <a 00460 * href="http://sourceforge.net/projects/tinydtls/files">downloads</a> section or 00461 * through git from the <a 00462 * href="http://sourceforge.net/projects/tinydtls/develop">project develop page</a>. 00463 * 00464 * @section config Configuration 00465 * 00466 * Use @c configure to set up everything for a successful build. For Contiki, use the 00467 * option @c --with-contiki. 00468 * 00469 * @section build Building 00470 * 00471 * After configuration, just type 00472 * @code 00473 make 00474 * @endcode 00475 * optionally followed by 00476 * @code 00477 make install 00478 * @endcode 00479 * The Contiki version is integrated with the Contiki build system, hence you do not 00480 * need to invoke @c make explicitely. Just add @c tinydtls to the variable @c APPS 00481 * in your @c Makefile. 00482 * 00483 * @addtogroup dtls_usage DTLS Usage 00484 * 00485 * @section dtls_server_example DTLS Server Example 00486 * 00487 * This section shows how to use the DTLS library functions to setup a 00488 * simple secure UDP echo server. The application is responsible for the 00489 * entire network communication and thus will look like a usual UDP 00490 * server with socket creation and binding and a typical select-loop as 00491 * shown below. The minimum configuration required for DTLS is the 00492 * creation of the dtls_context_t using dtls_new_context(), and a callback 00493 * for sending data. Received packets are read by the application and 00494 * passed to dtls_handle_message() as shown in @ref dtls_read_cb. 00495 * For any useful communication to happen, read and write call backs 00496 * and a key management function should be registered as well. 00497 * 00498 * @code 00499 dtls_context_t *the_context = NULL; 00500 int fd, result; 00501 00502 static dtls_handler_t cb = { 00503 .write = send_to_peer, 00504 .read = read_from_peer, 00505 .event = NULL, 00506 .get_psk_key = get_psk_key 00507 }; 00508 00509 fd = socket(...); 00510 if (fd < 0 || bind(fd, ...) < 0) 00511 exit(-1); 00512 00513 the_context = dtls_new_context(&fd); 00514 dtls_set_handler(the_context, &cb); 00515 00516 while (1) { 00517 ...initialize fd_set rfds and timeout ... 00518 result = select(fd+1, &rfds, NULL, 0, NULL); 00519 00520 if (FD_ISSET(fd, &rfds)) 00521 dtls_handle_read(the_context); 00522 } 00523 00524 dtls_free_context(the_context); 00525 * @endcode 00526 * 00527 * @subsection dtls_read_cb The Read Callback 00528 * 00529 * The DTLS library expects received raw data to be passed to 00530 * dtls_handle_message(). The application is responsible for 00531 * filling a session_t structure with the address data of the 00532 * remote peer as illustrated by the following example: 00533 * 00534 * @code 00535 int dtls_handle_read(struct dtls_context_t *ctx) { 00536 int *fd; 00537 session_t session; 00538 static uint8 buf[DTLS_MAX_BUF]; 00539 int len; 00540 00541 fd = dtls_get_app_data(ctx); 00542 00543 assert(fd); 00544 00545 session.size = sizeof(session.addr); 00546 len = recvfrom(*fd, buf, sizeof(buf), 0, &session.addr.sa, &session.size); 00547 00548 return len < 0 ? len : dtls_handle_message(ctx, &session, buf, len); 00549 } 00550 * @endcode 00551 * 00552 * Once a new DTLS session was established and DTLS ApplicationData has been 00553 * received, the DTLS server invokes the read callback with the MAC-verified 00554 * cleartext data as its argument. A read callback for a simple echo server 00555 * could look like this: 00556 * @code 00557 int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { 00558 return dtls_write(ctx, session, data, len); 00559 } 00560 * @endcode 00561 * 00562 * @subsection dtls_send_cb The Send Callback 00563 * 00564 * The callback function send_to_peer() is called whenever data must be 00565 * sent over the network. Here, the sendto() system call is used to 00566 * transmit data within the given session. The socket descriptor required 00567 * by sendto() has been registered as application data when the DTLS context 00568 * was created with dtls_new_context(). 00569 * Note that it is on the application to buffer the data when it cannot be 00570 * sent at the time this callback is invoked. The following example thus 00571 * is incomplete as it would have to deal with EAGAIN somehow. 00572 * @code 00573 int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { 00574 int fd = *(int *)dtls_get_app_data(ctx); 00575 return sendto(fd, data, len, MSG_DONTWAIT, &session->addr.sa, session->size); 00576 } 00577 * @endcode 00578 * 00579 * @subsection dtls_get_psk_key The Key Storage 00580 * 00581 * When a new DTLS session is created, the library must ask the application 00582 * for keying material. To do so, it invokes the registered call-back function 00583 * get_psk_key() with the current context and session information as parameter. 00584 * When the function is called with the @p id parameter set, the result must 00585 * point to a dtls_psk_key_t structure for the given identity. When @p id is 00586 * @c NULL, the function must pick a suitable identity and return a pointer to 00587 * the corresponding dtls_psk_key_t structure. The following example shows a 00588 * simple key storage for a pre-shared key for @c Client_identity: 00589 * 00590 * @code 00591 int get_psk_key(struct dtls_context_t *ctx, 00592 const session_t *session, 00593 const unsigned char *id, size_t id_len, 00594 const dtls_psk_key_t **result) { 00595 00596 static const dtls_psk_key_t psk = { 00597 .id = (unsigned char *)"my identity", 00598 .id_length = 11, 00599 .key = (unsigned char *)"secret", 00600 .key_length = 6 00601 }; 00602 00603 *result = &psk; 00604 return 0; 00605 } 00606 * @endcode 00607 * 00608 * @subsection dtls_events The Event Notifier 00609 * 00610 * Applications that want to be notified whenever the status of a DTLS session 00611 * has changed can register an event handling function with the field @c event 00612 * in the dtls_handler_t structure (see \ref dtls_server_example). The call-back 00613 * function is called for alert messages and internal state changes. For alert 00614 * messages, the argument @p level will be set to a value greate than zero, and 00615 * @p code will indicate the notification code. For internal events, @p level 00616 * is @c 0, and @p code a value greater than @c 255. 00617 * 00618 * Currently, the only defined internal event is @c DTLS_EVENT_CONNECTED. It 00619 * indicates successful establishment of a new DTLS channel. 00620 * 00621 * @code 00622 int handle_event(struct dtls_context_t *ctx, session_t *session, 00623 dtls_alert_level_t level, unsigned short code) { 00624 ... do something with event ... 00625 return 0; 00626 } 00627 * @endcode 00628 * 00629 * @section dtls_client_example DTLS Client Example 00630 * 00631 * A DTLS client is constructed like a server but needs to actively setup 00632 * a new session by calling dtls_connect() at some point. As this function 00633 * usually returns before the new DTLS channel is established, the application 00634 * must register an event handler and wait for @c DTLS_EVENT_CONNECT before 00635 * it can send data over the DTLS channel. 00636 * 00637 */ 00638 00639 /** 00640 * @addtogroup contiki Contiki 00641 * 00642 * To use tinyDTLS as Contiki application, place the source code in the directory 00643 * @c apps/tinydtls in the Contiki source tree and invoke configure with the option 00644 * @c --with-contiki. This will create the tinydtls Makefile and config.h from the 00645 * templates @c Makefile.contiki and @c config.h.contiki instead of the usual 00646 * templates ending in @c .in. 00647 * 00648 * Then, create a Contiki project with @c APPS += tinydtls in its Makefile. A sample 00649 * server could look like this (with read_from_peer() and get_psk_key() as shown above). 00650 * 00651 * @code 00652 #include "contiki.h" 00653 00654 #include "config.h" 00655 #include "dtls.h" 00656 00657 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) 00658 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) 00659 00660 int send_to_peer(struct dtls_context_t *, session_t *, uint8 *, size_t); 00661 00662 static struct uip_udp_conn *server_conn; 00663 static dtls_context_t *dtls_context; 00664 00665 static dtls_handler_t cb = { 00666 .write = send_to_peer, 00667 .read = read_from_peer, 00668 .event = NULL, 00669 .get_psk_key = get_psk_key 00670 }; 00671 00672 PROCESS(server_process, "DTLS server process"); 00673 AUTOSTART_PROCESSES(&server_process); 00674 00675 PROCESS_THREAD(server_process, ev, data) 00676 { 00677 PROCESS_BEGIN(); 00678 00679 dtls_init(); 00680 00681 server_conn = udp_new(NULL, 0, NULL); 00682 udp_bind(server_conn, UIP_HTONS(5684)); 00683 00684 dtls_context = dtls_new_context(server_conn); 00685 if (!dtls_context) { 00686 dsrv_log(LOG_EMERG, "cannot create context\n"); 00687 PROCESS_EXIT(); 00688 } 00689 00690 dtls_set_handler(dtls_context, &cb); 00691 00692 while(1) { 00693 PROCESS_WAIT_EVENT(); 00694 if(ev == tcpip_event && uip_newdata()) { 00695 session_t session; 00696 00697 uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr); 00698 session.port = UIP_UDP_BUF->srcport; 00699 session.size = sizeof(session.addr) + sizeof(session.port); 00700 00701 dtls_handle_message(ctx, &session, uip_appdata, uip_datalen()); 00702 } 00703 } 00704 00705 PROCESS_END(); 00706 } 00707 00708 int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) { 00709 struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx); 00710 00711 uip_ipaddr_copy(&conn->ripaddr, &session->addr); 00712 conn->rport = session->port; 00713 00714 uip_udp_packet_send(conn, data, len); 00715 00716 memset(&conn->ripaddr, 0, sizeof(server_conn->ripaddr)); 00717 memset(&conn->rport, 0, sizeof(conn->rport)); 00718 00719 return len; 00720 } 00721 * @endcode 00722 */ 00723 00724 #ifdef __cplusplus 00725 } 00726 #endif 00727 00728 #endif /* _DTLS_H_ */
Generated on Tue Jul 12 2022 21:37:38 by 1.7.2