Version 0.5.0 of tinydtls

Dependents:   tinydtls_test_cellular tinydtls_test_ethernet tiny-dtls

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dtls.h Source File

dtls.h

Go to the documentation of this file.
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_ */