1 /* dtls -- a very basic DTLS implementation
3 * Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org>
4 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 * @brief High level DTLS API and visible structures.
44 #endif /* WITH_CONTIKI */
51 #include "dtls_time.h"
54 #define DTLS_VERSION 0xfeff /* DTLS v1.1 */
56 #define DTLS_VERSION 0xfefd /* DTLS v1.2 */
60 #define DTLS_MAX_CERT_SIZE 1400
63 typedef enum dtls_credentials_type_t {
64 DTLS_PSK_HINT, DTLS_PSK_IDENTITY, DTLS_PSK_KEY
65 } dtls_credentials_type_t;
67 typedef struct dtls_ecc_key_t {
68 dtls_ecdh_curve curve;
69 const unsigned char *priv_key; /** < private key as bytes > */
70 const unsigned char *pub_key_x; /** < x part of the public key for the given private key > */
71 const unsigned char *pub_key_y; /** < y part of the public key for the given private key > */
74 /** Length of the secret that is used for generating Hello Verify cookies. */
75 #define DTLS_COOKIE_SECRET_LENGTH 12
77 struct dtls_context_t;
80 * This structure contains callback functions used by tinydtls to
81 * communicate with the application. At least the write function must
82 * be provided. It is called by the DTLS state machine to send packets
83 * over the network. The read function is invoked to deliver decrypted
84 * and verfified application data. The third callback is an event
85 * handler function that is called when alert messages are encountered
86 * or events generated by the library have occured.
90 * Called from dtls_handle_message() to send DTLS packets over the
91 * network. The callback function must use the network interface
92 * denoted by session->ifindex to send the data.
94 * @param ctx The current DTLS context.
95 * @param session The session object, including the address of the
96 * remote peer where the data shall be sent.
97 * @param buf The data to send.
98 * @param len The actual length of @p buf.
99 * @return The callback function must return the number of bytes
100 * that were sent, or a value less than zero to indicate an
103 int (*write)(struct dtls_context_t *ctx,
104 session_t *session, uint8 *buf, size_t len);
107 * Called from dtls_handle_message() deliver application data that was
108 * received on the given session. The data is delivered only after
109 * decryption and verification have succeeded.
111 * @param ctx The current DTLS context.
112 * @param session The session object, including the address of the
114 * @param buf The received data packet.
115 * @param len The actual length of @p buf.
118 int (*read)(struct dtls_context_t *ctx,
119 session_t *session, uint8 *buf, size_t len);
122 * The event handler is called when a message from the alert
123 * protocol is received or the state of the DTLS session changes.
125 * @param ctx The current dtls context.
126 * @param session The session object that was affected.
127 * @param level The alert level or @c 0 when an event ocurred that
129 * @param code Values less than @c 256 indicate alerts, while
130 * @c 256 or greater indicate internal DTLS session changes.
133 int (*event)(struct dtls_context_t *ctx, session_t *session,
134 dtls_alert_level_t level, unsigned short code);
138 * Called during handshake to get information related to the
139 * psk key exchange. The type of information requested is
140 * indicated by @p type which will be one of DTLS_PSK_HINT,
141 * DTLS_PSK_IDENTITY, or DTLS_PSK_KEY. The called function
142 * must store the requested item in the buffer @p result of
143 * size @p result_length. On success, the function must return
144 * the actual number of bytes written to @p result, of a
145 * value less than zero on error. The parameter @p desc may
146 * contain additional request information (e.g. the psk_identity
147 * for which a key is requested when @p type == @c DTLS_PSK_KEY.
149 * @param ctx The current dtls context.
150 * @param session The session where the key will be used.
151 * @param type The type of the requested information.
152 * @param desc Additional request information
153 * @param desc_len The actual length of desc.
154 * @param result Must be filled with the requested information.
155 * @param result_length Maximum size of @p result.
156 * @return The number of bytes written to @p result or a value
157 * less than zero on error.
159 int (*get_psk_info)(struct dtls_context_t *ctx,
160 const session_t *session,
161 dtls_credentials_type_t type,
162 const unsigned char *desc, size_t desc_len,
163 unsigned char *result, size_t result_length);
165 #endif /* DTLS_PSK */
169 * Called during handshake to get the server's or client's ecdsa
170 * key used to authenticate this server or client in this
171 * session. If found, the key must be stored in @p result and
172 * the return value must be @c 0. If not found, @p result is
173 * undefined and the return value must be less than zero.
175 * If ECDSA should not be supported, set this pointer to NULL.
177 * Implement this if you want to provide your own certificate to
178 * the other peer. This is mandatory for a server providing ECDSA
179 * support and optional for a client. A client doing DTLS client
180 * authentication has to implementing this callback.
182 * @param ctx The current dtls context.
183 * @param session The session where the key will be used.
184 * @param result Must be set to the key object to used for the given
186 * @return @c 0 if result is set, or less than zero on error.
188 int (*get_ecdsa_key)(struct dtls_context_t *ctx,
189 const session_t *session,
190 const dtls_ecc_key_t **result);
194 * Called during handshake to check the peer's pubic key in this
195 * session. If the public key matches the session and should be
196 * considered valid the return value must be @c 0. If not valid,
197 * the return value must be less than zero.
199 * If ECDSA should not be supported, set this pointer to NULL.
201 * Implement this if you want to verify the other peers public key.
202 * This is mandatory for a DTLS client doing based ECDSA
203 * authentication. A server implementing this will request the
204 * client to do DTLS client authentication.
206 * @param ctx The current dtls context.
207 * @param session The session where the key will be used.
208 * @param other_pub_x x component of the public key.
209 * @param other_pub_y y component of the public key.
210 * @return @c 0 if public key matches, or less than zero on error.
212 * return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE);
213 * return dtls_alert_fatal_create(DTLS_ALERT_UNSUPPORTED_CERTIFICATE);
214 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_REVOKED);
215 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_EXPIRED);
216 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_UNKNOWN);
217 * return dtls_alert_fatal_create(DTLS_ALERT_UNKNOWN_CA);
219 int (*verify_ecdsa_key)(struct dtls_context_t *ctx,
220 const session_t *session,
221 const unsigned char *other_pub_x,
222 const unsigned char *other_pub_y,
224 #endif /* DTLS_ECC */
227 * Called during handshake to get the server's or client's ecdsa
228 * key used to authenticate this server or client in this
229 * session. If found, the key must be stored in @p result and
230 * the return value must be @c 0. If not found, @p result is
231 * undefined and the return value must be less than zero.
233 * If ECDSA should not be supported, set this pointer to NULL.
235 * Implement this if you want to provide your own certificate to
236 * the other peer. This is mandatory for a server providing X.509
237 * support and optional for a client. A client doing DTLS client
238 * authentication has to implementing this callback.
240 * @param ctx The current dtls context.
241 * @param session The session where the key will be used.
242 * @param result Must be set to the key object to used for the given
244 * @return @c 0 if result is set, or less than zero on error.
246 int (*get_x509_key)(struct dtls_context_t *ctx,
247 const session_t *session,
248 const dtls_ecc_key_t **result);
250 * Called during handshake to get the server's or client's
251 * certificate used to authenticate this server or client in this
252 * session. If found, the certificate must be stored in @p cert and
253 * the return value must be @c 0. If not found, @p cert is
254 * undefined and the return value must be less than zero.
256 * If X.509 should not be supported, set this pointer to NULL.
258 * Implement this if you want to provide your own certificate to
259 * the other peer. This is mandatory for a server providing X.509
260 * support and optional for a client. A client doing DTLS client
261 * authentication has to implementing this callback.
263 * @param ctx The current dtls context.
264 * @param session The session where the certificate will be used.
265 * @param cert Must be set to the certificate object to used for
267 * @param cert_size Size of certificate in bytes.
268 * @return @c 0 if result is set, or less than zero on error.
270 int (*get_x509_cert)(struct dtls_context_t *ctx,
271 const session_t *session,
272 const unsigned char **cert,
276 * Called during handshake to check the peer's certificate in this
277 * session. If the certificate matches the session and is valid the
278 * return value must be @c 0. If not valid, the return value must be
281 * If X.509 should not be supported, set this pointer to NULL.
283 * Implement this if you want to verify the other peers certificate.
284 * This is mandatory for a DTLS client doing based X.509
285 * authentication. A server implementing this will request the
286 * client to do DTLS client authentication.
288 * @param ctx The current dtls context.
289 * @param session The session where the key will be used.
290 * @param cert Peer's certificate to check.
291 * @param cert_size Size of certificate in bytes.
292 * @param x Allocated memory to store peer's public key part x.
293 * @param x_size Size of allocated memory to store peer's public key part x.
294 * @param y Allocated memory to store peer's public key part y.
295 * @param y_size Size of allocated memory to store peer's public key part y.
296 * @return @c 0 if public key matches, or less than zero on error.
298 * return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE);
299 * return dtls_alert_fatal_create(DTLS_ALERT_UNSUPPORTED_CERTIFICATE);
300 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_REVOKED);
301 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_EXPIRED);
302 * return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_UNKNOWN);
303 * return dtls_alert_fatal_create(DTLS_ALERT_UNKNOWN_CA);
305 int (*verify_x509_cert)(struct dtls_context_t *ctx,
306 const session_t *session,
307 const unsigned char *cert,
315 * Called during handshake to check if certificate format should be X.509
317 * If X.509 should not be supported, set this pointer to NULL.
319 * @param ctx The current dtls context.
320 * @return @c 0 if certificate format should be X.509, or less than zero on error.
322 int (*is_x509_active)(struct dtls_context_t *ctx);
323 #endif /* DTLS_X509 */
327 /** Holds global information of the DTLS engine. */
328 typedef struct dtls_context_t {
329 unsigned char cookie_secret[DTLS_COOKIE_SECRET_LENGTH];
330 clock_time_t cookie_secret_age; /**< the time the secret has been generated */
333 dtls_peer_t *peers; /**< peer hash map */
334 #else /* WITH_CONTIKI */
337 struct etimer retransmit_timer; /**< fires when the next packet must be sent */
338 #endif /* WITH_CONTIKI */
340 LIST_STRUCT(sendqueue); /**< the packets to send */
342 void *app; /**< application-specific data */
344 dtls_handler_t *h; /**< callback handlers */
346 dtls_cipher_enable_t is_anon_ecdh_eabled; /**< enable/disable the TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */
348 dtls_cipher_t selected_cipher; /**< selected ciper suite for handshake */
350 unsigned char readbuf[DTLS_MAX_BUF];
354 * This function initializes the tinyDTLS memory management and must
360 * Creates a new context object. The storage allocated for the new
361 * object must be released with dtls_free_context(). */
362 dtls_context_t *dtls_new_context(void *app_data);
364 /** Releases any storage that has been allocated for \p ctx. */
365 void dtls_free_context(dtls_context_t *ctx);
367 #define dtls_set_app_data(CTX,DATA) ((CTX)->app = (DATA))
368 #define dtls_get_app_data(CTX) ((CTX)->app)
370 /** Sets the callback handler object for @p ctx to @p h. */
371 INLINE_API void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) {
376 * @brief Enabling the TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256
378 * @param ctx The DTLS context to use.
379 * @param is_enable DTLS_CIPHER_ENABLE(1) or DTLS_CIPHER_DISABLE(0)
381 void dtls_enables_anon_ecdh(dtls_context_t* ctx, dtls_cipher_enable_t is_enable);
384 * @brief Select the cipher suite for handshake
386 * @param ctx The DTLS context to use.
387 * @param cipher TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 (0xC018)
388 * TLS_PSK_WITH_AES_128_CCM_8 (0xX0A8)
389 * TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (0xC0AE)
391 void dtls_select_cipher(dtls_context_t* ctx, const dtls_cipher_t cipher);
394 * Establishes a DTLS channel with the specified remote peer @p dst.
395 * This function returns @c 0 if that channel already exists, a value
396 * greater than zero when a new ClientHello message was sent, and
397 * a value less than zero on error.
399 * @param ctx The DTLS context to use.
400 * @param dst The remote party to connect to.
401 * @return A value less than zero on error, greater or equal otherwise.
403 int dtls_connect(dtls_context_t *ctx, const session_t *dst);
406 * Establishes a DTLS channel with the specified remote peer.
407 * This function returns @c 0 if that channel already exists, a value
408 * greater than zero when a new ClientHello message was sent, and
409 * a value less than zero on error.
411 * @param ctx The DTLS context to use.
412 * @param peer The peer object that describes the session.
413 * @return A value less than zero on error, greater or equal otherwise.
415 int dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer);
418 * Closes the DTLS connection associated with @p remote. This function
419 * returns zero on success, and a value less than zero on error.
421 int dtls_close(dtls_context_t *ctx, const session_t *remote);
423 int dtls_renegotiate(dtls_context_t *ctx, const session_t *dst);
426 * Writes the application data given in @p buf to the peer specified
429 * @param ctx The DTLS context to use.
430 * @param session The remote transport address and local interface.
431 * @param buf The data to write.
432 * @param len The actual length of @p data.
434 * @return The number of bytes written or @c -1 on error.
436 int dtls_write(struct dtls_context_t *ctx, session_t *session,
437 uint8 *buf, size_t len);
440 * Checks sendqueue of given DTLS context object for any outstanding
441 * packets to be transmitted.
443 * @param context The DTLS context object to use.
444 * @param next If not NULL, @p next is filled with the timestamp
445 * of the next scheduled retransmission, or @c 0 when no packets are
448 void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next);
450 #define DTLS_COOKIE_LENGTH 16
452 #define DTLS_CT_CHANGE_CIPHER_SPEC 20
453 #define DTLS_CT_ALERT 21
454 #define DTLS_CT_HANDSHAKE 22
455 #define DTLS_CT_APPLICATION_DATA 23
457 #if defined(_MSC_VER)
458 #define PACKED_STRUCT_START __pragma(pack(push,1)); typedef struct
459 #define PACKED_STRUCT_END __pragma(pack(pop))
461 #define PACKED_STRUCT_START typedef struct __attribute__((__packed__))
462 #define PACKED_STRUCT_END
465 /** Generic header structure of the DTLS record layer. */
466 PACKED_STRUCT_START {
467 uint8 content_type; /**< content type of the included message */
468 uint16 version; /**< Protocol version */
469 uint16 epoch; /**< counter for cipher state changes */
470 uint48 sequence_number; /**< sequence number */
471 uint16 length; /**< length of the following fragment */
473 } dtls_record_header_t;
476 /* Handshake types */
478 #define DTLS_HT_HELLO_REQUEST 0
479 #define DTLS_HT_CLIENT_HELLO 1
480 #define DTLS_HT_SERVER_HELLO 2
481 #define DTLS_HT_HELLO_VERIFY_REQUEST 3
482 #define DTLS_HT_CERTIFICATE 11
483 #define DTLS_HT_SERVER_KEY_EXCHANGE 12
484 #define DTLS_HT_CERTIFICATE_REQUEST 13
485 #define DTLS_HT_SERVER_HELLO_DONE 14
486 #define DTLS_HT_CERTIFICATE_VERIFY 15
487 #define DTLS_HT_CLIENT_KEY_EXCHANGE 16
488 #define DTLS_HT_FINISHED 20
490 /** Header structure for the DTLS handshake protocol. */
491 PACKED_STRUCT_START {
492 uint8 msg_type; /**< Type of handshake message (one of DTLS_HT_) */
493 uint24 length; /**< length of this message */
494 uint16 message_seq; /**< Message sequence number */
495 uint24 fragment_offset; /**< Fragment offset. */
496 uint24 fragment_length; /**< Fragment length. */
498 } dtls_handshake_header_t;
501 /** Structure of the Client Hello message. */
502 PACKED_STRUCT_START {
503 uint16 version; /**< Client version */
504 uint32 gmt_random; /**< GMT time of the random byte creation */
505 unsigned char random[28]; /**< Client random bytes */
506 /* session id (up to 32 bytes) */
507 /* cookie (up to 32 bytes) */
508 /* cipher suite (2 to 2^16 -1 bytes) */
509 /* compression method */
510 } dtls_client_hello_t;
513 /** Structure of the Hello Verify Request. */
514 PACKED_STRUCT_START {
515 uint16 version; /**< Server version */
516 uint8 cookie_length; /**< Length of the included cookie */
517 uint8 cookie[]; /**< up to 32 bytes making up the cookie */
518 } dtls_hello_verify_t;
523 * Checks a received DTLS record for consistency and eventually decrypt,
524 * verify, decompress and reassemble the contained fragment for
525 * delivery to high-lever clients.
527 * \param state The DTLS record state for the current session.
530 int dtls_record_read(dtls_state_t *state, uint8 *msg, int msglen);
534 * Handles incoming data as DTLS message from given peer.
536 * @param ctx The dtls context to use.
537 * @param session The current session
538 * @param msg The received data
539 * @param msglen The actual length of @p msg.
540 * @return A value less than zero on error, zero on success.
542 int dtls_handle_message(dtls_context_t *ctx, session_t *session,
543 uint8 *msg, int msglen);
546 * Check if @p session is associated with a peer object in @p context.
547 * This function returns a pointer to the peer if found, NULL otherwise.
549 * @param context The DTLS context to search.
550 * @param session The remote address and local interface
551 * @return A pointer to the peer associated with @p session or NULL if
554 dtls_peer_t *dtls_get_peer(const dtls_context_t *context,
555 const session_t *session);
558 * Invokes the DTLS PRF using the current key block for @p session as
559 * key and @p label + @p random1 + @p random2 as its input. This function
560 * writes upto @p buflen bytes into the given output buffer @p buf.
562 * @param ctx The dtls context to use.
563 * @param session The session whose key shall be used.
564 * @param label A PRF label.
565 * @param labellen Actual length of @p label.
566 * @param random1 Random seed.
567 * @param random1len Actual length of @p random1 (may be zero).
568 * @param random2 Random seed.
569 * @param random2len Actual length of @p random2 (may be zero).
570 * @param buf Output buffer for generated random data.
571 * @param buflen Maximum size of @p buf.
573 * @return The actual number of bytes written to @p buf or @c 0 on error.
575 size_t dtls_prf_with_current_keyblock(dtls_context_t *ctx, session_t *session,
576 const uint8_t* label, const uint32_t labellen,
577 const uint8_t* random1, const uint32_t random1len,
578 const uint8_t* random2, const uint32_t random2len,
579 uint8_t* buf, const uint32_t buflen);
582 #endif /* _DTLS_DTLS_H_ */
587 * @author Olaf Bergmann, TZI Uni Bremen
589 * This library provides a very simple datagram server with DTLS
590 * support. It is designed to support session multiplexing in
591 * single-threaded applications and thus targets specifically on
594 * @section license License
596 * This software is under the <a
597 * href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>.
599 * @subsection uthash UTHash
601 * This library uses <a href="http://uthash.sourceforge.net/">uthash</a> to manage
602 * its peers (not used for Contiki). @b uthash uses the <b>BSD revised license</b>, see
603 * <a href="http://uthash.sourceforge.net/license.html">http://uthash.sourceforge.net/license.html</a>.
605 * @subsection sha256 Aaron D. Gifford's SHA256 Implementation
607 * tinyDTLS provides HMAC-SHA256 with BSD-licensed code from Aaron D. Gifford,
608 * see <a href="http://www.aarongifford.com/">www.aarongifford.com</a>.
610 * @subsection aes Rijndael Implementation From OpenBSD
612 * The AES implementation is taken from rijndael.{c,h} contained in the crypto
613 * sub-system of the OpenBSD operating system. It is copyright by Vincent Rijmen, *
614 * Antoon Bosselaers and Paulo Barreto. See <a
615 * href="http://www.openbsd.org/cgi-bin/cvsweb/src/sys/crypto/rijndael.c">rijndael.c</a>
618 * @section download Getting the Files
620 * You can get the sources either from the <a
621 * href="http://sourceforge.net/projects/tinydtls/files">downloads</a> section or
622 * through git from the <a
623 * href="http://sourceforge.net/projects/tinydtls/develop">project develop page</a>.
625 * @section config Configuration
627 * Use @c configure to set up everything for a successful build. For Contiki, use the
628 * option @c --with-contiki.
630 * @section build Building
632 * After configuration, just type
636 * optionally followed by
640 * The Contiki version is integrated with the Contiki build system, hence you do not
641 * need to invoke @c make explicitely. Just add @c tinydtls to the variable @c APPS
642 * in your @c Makefile.
644 * @addtogroup dtls_usage DTLS Usage
646 * @section dtls_server_example DTLS Server Example
648 * This section shows how to use the DTLS library functions to setup a
649 * simple secure UDP echo server. The application is responsible for the
650 * entire network communication and thus will look like a usual UDP
651 * server with socket creation and binding and a typical select-loop as
652 * shown below. The minimum configuration required for DTLS is the
653 * creation of the dtls_context_t using dtls_new_context(), and a callback
654 * for sending data. Received packets are read by the application and
655 * passed to dtls_handle_message() as shown in @ref dtls_read_cb.
656 * For any useful communication to happen, read and write call backs
657 * and a key management function should be registered as well.
660 dtls_context_t *the_context = NULL;
663 static dtls_handler_t cb = {
664 .write = send_to_peer,
665 .read = read_from_peer,
667 .get_psk_key = get_psk_key
671 if (fd < 0 || bind(fd, ...) < 0)
674 the_context = dtls_new_context(&fd);
675 dtls_set_handler(the_context, &cb);
678 ...initialize fd_set rfds and timeout ...
679 result = select(fd+1, &rfds, NULL, 0, NULL);
681 if (FD_ISSET(fd, &rfds))
682 dtls_handle_read(the_context);
685 dtls_free_context(the_context);
688 * @subsection dtls_read_cb The Read Callback
690 * The DTLS library expects received raw data to be passed to
691 * dtls_handle_message(). The application is responsible for
692 * filling a session_t structure with the address data of the
693 * remote peer as illustrated by the following example:
696 int dtls_handle_read(struct dtls_context_t *ctx) {
699 static uint8 buf[DTLS_MAX_BUF];
702 fd = dtls_get_app_data(ctx);
706 session.size = sizeof(session.addr);
707 len = recvfrom(*fd, buf, sizeof(buf), 0, &session.addr.sa, &session.size);
709 return len < 0 ? len : dtls_handle_message(ctx, &session, buf, len);
713 * Once a new DTLS session was established and DTLS ApplicationData has been
714 * received, the DTLS server invokes the read callback with the MAC-verified
715 * cleartext data as its argument. A read callback for a simple echo server
716 * could look like this:
718 int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
719 return dtls_write(ctx, session, data, len);
723 * @subsection dtls_send_cb The Send Callback
725 * The callback function send_to_peer() is called whenever data must be
726 * sent over the network. Here, the sendto() system call is used to
727 * transmit data within the given session. The socket descriptor required
728 * by sendto() has been registered as application data when the DTLS context
729 * was created with dtls_new_context().
730 * Note that it is on the application to buffer the data when it cannot be
731 * sent at the time this callback is invoked. The following example thus
732 * is incomplete as it would have to deal with EAGAIN somehow.
734 int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
735 int fd = *(int *)dtls_get_app_data(ctx);
736 return sendto(fd, data, len, MSG_DONTWAIT, &session->addr.sa, session->size);
740 * @subsection dtls_get_psk_info The Key Storage
742 * When a new DTLS session is created, the library must ask the application
743 * for keying material. To do so, it invokes the registered call-back function
744 * get_psk_info() with the current context and session information as parameter.
745 * When the call-back function is invoked with the parameter @p type set to
746 * @c DTLS_PSK_IDENTITY, the result parameter @p result must be filled with
747 * the psk_identity_hint in case of a server, or the actual psk_identity in
748 * case of a client. When @p type is @c DTLS_PSK_KEY, the result parameter
749 * must be filled with a key for the given identity @p id. The function must
750 * return the number of bytes written to @p result which must not exceed
752 * In case of an error, the function must return a negative value that
753 * corresponds to a valid error code defined in alert.h.
756 int get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
757 const session_t *session UNUSED_PARAM,
758 dtls_credentials_type_t type,
759 const unsigned char *id, size_t id_len,
760 unsigned char *result, size_t result_length) {
763 case DTLS_PSK_IDENTITY:
764 if (result_length < psk_id_length) {
765 dtls_warn("cannot set psk_identity -- buffer too small\n");
766 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
769 memcpy(result, psk_id, psk_id_length);
770 return psk_id_length;
772 if (id_len != psk_id_length || memcmp(psk_id, id, id_len) != 0) {
773 dtls_warn("PSK for unknown id requested, exiting\n");
774 return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER);
775 } else if (result_length < psk_key_length) {
776 dtls_warn("cannot set psk -- buffer too small\n");
777 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
780 memcpy(result, psk_key, psk_key_length);
781 return psk_key_length;
783 dtls_warn("unsupported request type: %d\n", type);
786 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
790 * @subsection dtls_events The Event Notifier
792 * Applications that want to be notified whenever the status of a DTLS session
793 * has changed can register an event handling function with the field @c event
794 * in the dtls_handler_t structure (see \ref dtls_server_example). The call-back
795 * function is called for alert messages and internal state changes. For alert
796 * messages, the argument @p level will be set to a value greater than zero, and
797 * @p code will indicate the notification code. For internal events, @p level
798 * is @c 0, and @p code a value greater than @c 255.
800 * Internal events are DTLS_EVENT_CONNECTED, @c DTLS_EVENT_CONNECT, and
801 * @c DTLS_EVENT_RENEGOTIATE.
804 int handle_event(struct dtls_context_t *ctx, session_t *session,
805 dtls_alert_level_t level, unsigned short code) {
806 ... do something with event ...
811 * @section dtls_client_example DTLS Client Example
813 * A DTLS client is constructed like a server but needs to actively setup
814 * a new session by calling dtls_connect() at some point. As this function
815 * usually returns before the new DTLS channel is established, the application
816 * must register an event handler and wait for @c DTLS_EVENT_CONNECT before
817 * it can send data over the DTLS channel.
822 * @addtogroup contiki Contiki
824 * To use tinyDTLS as Contiki application, place the source code in the directory
825 * @c apps/tinydtls in the Contiki source tree and invoke configure with the option
826 * @c --with-contiki. This will define WITH_CONTIKI in tinydtls.h and include
827 * @c Makefile.contiki in the main Makefile. To cross-compile for another platform
828 * you will need to set your host and build system accordingly. For example,
829 * when configuring for ARM, you would invoke
831 ./configure --with-contiki --build=x86_64-linux-gnu --host=arm-none-eabi
833 * on an x86_64 linux host.
835 * Then, create a Contiki project with @c APPS += tinydtls in its Makefile. A sample
836 * server could look like this (with read_from_peer() and get_psk_key() as shown above).
841 #include "tinydtls.h"
844 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
845 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
847 int send_to_peer(struct dtls_context_t *, session_t *, uint8 *, size_t);
849 static struct uip_udp_conn *server_conn;
850 static dtls_context_t *dtls_context;
852 static dtls_handler_t cb = {
853 .write = send_to_peer,
854 .read = read_from_peer,
856 .get_psk_key = get_psk_key
859 PROCESS(server_process, "DTLS server process");
860 AUTOSTART_PROCESSES(&server_process);
862 PROCESS_THREAD(server_process, ev, data)
868 server_conn = udp_new(NULL, 0, NULL);
869 udp_bind(server_conn, UIP_HTONS(5684));
871 dtls_context = dtls_new_context(server_conn);
873 dtls_emerg("cannot create context\n");
877 dtls_set_handler(dtls_context, &cb);
880 PROCESS_WAIT_EVENT();
881 if(ev == tcpip_event && uip_newdata()) {
884 uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
885 session.port = UIP_UDP_BUF->srcport;
886 session.size = sizeof(session.addr) + sizeof(session.port);
888 dtls_handle_message(ctx, &session, uip_appdata, uip_datalen());
895 int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
896 struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
898 uip_ipaddr_copy(&conn->ripaddr, &session->addr);
899 conn->rport = session->port;
901 uip_udp_packet_send(conn, data, len);
903 memset(&conn->ripaddr, 0, sizeof(server_conn->ripaddr));
904 memset(&conn->rport, 0, sizeof(conn->rport));