-
Notifications
You must be signed in to change notification settings - Fork 2
/
dtls.h
826 lines (732 loc) · 29.9 KB
/
dtls.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
/* dtls -- a very basic DTLS implementation
*
* Copyright (C) 2011--2013 Olaf Bergmann <bergmann@tzi.org>
* Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* @file dtls.h
* @brief High level DTLS API and visible structures.
*/
#ifndef _DTLS_DTLS_H_
#define _DTLS_DTLS_H_
#include <stdint.h>
#include "t_list.h"
#include "state.h"
#include "peer.h"
#ifndef WITH_CONTIKI
#include "uthash.h"
#include "t_list.h"
#endif /* WITH_CONTIKI */
#include "alert.h"
#include "tinydtls-crypto.h"
#include "hmac.h"
#include "global.h"
#include "dtls_time.h"
#ifndef DTLSv12
#define DTLS_VERSION 0xfeff /* DTLS v1.1 */
#else
#define DTLS_VERSION 0xfefd /* DTLS v1.2 */
#endif
typedef enum dtls_credentials_type_t {
DTLS_PSK_HINT, DTLS_PSK_IDENTITY, DTLS_PSK_KEY
} dtls_credentials_type_t;
typedef struct dtls_ecdsa_key_t {
dtls_ecdh_curve curve;
const unsigned char *priv_key; /** < private key as bytes > */
const unsigned char *pub_key_x; /** < x part of the public key for the given private key > */
const unsigned char *pub_key_y; /** < y part of the public key for the given private key > */
const unsigned char *ca_id; /* CA identity (root CA) */
uint8_t ca_id_length; /* CA identity length */
} dtls_ecdsa_key_t;
typedef struct dtls_ecdsa_certificate_t {
#if EST_WITH_DTLS
unsigned char priv_key[DTLS_EC_KEY_SIZE]; /* Certificate's private key */
#else
const unsigned char *priv_key; /* Certificate's private key */
#endif
const unsigned char *certificate; /* Certificate */
size_t certificate_length; /* length of Certificate */
} dtls_ecdsa_certificate_t;
typedef struct dtls_ca_info_t {
const unsigned char *ca_id; /* CA identity (root CA) */
uint8_t ca_id_length; /* CA identity length */
const unsigned char *ca_public_key; /* CA public key */
} dtls_ca_info_t;
/** Length of the secret that is used for generating Hello Verify cookies. */
#define DTLS_COOKIE_SECRET_LENGTH 12
struct dtls_context_t;
/**
* This structure contains callback functions used by tinydtls to
* communicate with the application. At least the write function must
* be provided. It is called by the DTLS state machine to send packets
* over the network. The read function is invoked to deliver decrypted
* and verfified application data. The third callback is an event
* handler function that is called when alert messages are encountered
* or events generated by the library have occured.
*/
typedef struct {
/**
* Called from dtls_handle_message() to send DTLS packets over the
* network. The callback function must use the network interface
* denoted by session->ifindex to send the data.
*
* @param ctx The current DTLS context.
* @param session The session object, including the address of the
* remote peer where the data shall be sent.
* @param buf The data to send.
* @param len The actual length of @p buf.
* @return The callback function must return the number of bytes
* that were sent, or a value less than zero to indicate an
* error.
*/
int (*write)(struct dtls_context_t *ctx,
session_t *session, uint8 *buf, size_t len);
/**
* Called from dtls_handle_message() deliver application data that was
* received on the given session. The data is delivered only after
* decryption and verification have succeeded.
*
* @param ctx The current DTLS context.
* @param session The session object, including the address of the
* data's origin.
* @param buf The received data packet.
* @param len The actual length of @p buf.
* @return ignored
*/
int (*read)(struct dtls_context_t *ctx,
session_t *session, uint8 *buf, size_t len);
/**
* The event handler is called when a message from the alert
* protocol is received or the state of the DTLS session changes.
*
* @param ctx The current dtls context.
* @param session The session object that was affected.
* @param level The alert level or @c 0 when an event ocurred that
* is not an alert.
* @param code Values less than @c 256 indicate alerts, while
* @c 256 or greater indicate internal DTLS session changes.
* @return ignored
*/
int (*event)(struct dtls_context_t *ctx, session_t *session,
dtls_alert_level_t level, unsigned short code);
#ifdef DTLS_PSK
/**
* Called during handshake to get information related to the
* psk key exchange. The type of information requested is
* indicated by @p type which will be one of DTLS_PSK_HINT,
* DTLS_PSK_IDENTITY, or DTLS_PSK_KEY. The called function
* must store the requested item in the buffer @p result of
* size @p result_length. On success, the function must return
* the actual number of bytes written to @p result, of a
* value less than zero on error. The parameter @p desc may
* contain additional request information (e.g. the psk_identity
* for which a key is requested when @p type == @c DTLS_PSK_KEY.
*
* @param ctx The current dtls context.
* @param session The session where the key will be used.
* @param type The type of the requested information.
* @param desc Additional request information
* @param desc_len The actual length of desc.
* @param result Must be filled with the requested information.
* @param result_length Maximum size of @p result.
* @return The number of bytes written to @p result or a value
* less than zero on error.
*/
int (*get_psk_info)(struct dtls_context_t *ctx,
const session_t *session,
dtls_credentials_type_t type,
const unsigned char *desc, size_t desc_len,
unsigned char *result, size_t result_length);
#endif /* DTLS_PSK */
#ifdef DTLS_ECC
/**
* Called during handshake to get the server's or client's ecdsa
* key used to authenticate this server or client in this
* session. If found, the key must be stored in @p result and
* the return value must be @c 0. If not found, @p result is
* undefined and the return value must be less than zero.
*
* If ECDSA should not be supported, set this pointer to NULL.
*
* Implement this if you want to provide your own certificate to
* the other peer. This is mandatory for a server providing ECDSA
* support and optional for a client. A client doing DTLS client
* authentication has to implementing this callback.
*
* @param ctx The current dtls context.
* @param session The session where the key will be used.
* @param result Must be set to the key object to used for the given
* session.
* @return @c 0 if result is set, or less than zero on error.
*/
int (*get_ecdsa_key)(struct dtls_context_t *ctx,
const session_t *session,
const dtls_ecdsa_key_t **result);
/**
* Called during handshake to check the peer's pubic key in this
* session. If the public key matches the session and should be
* considerated valid the return value must be @c 0. If not valid,
* the return value must be less than zero.
*
* If ECDSA should not be supported, set this pointer to NULL.
*
* Implement this if you want to verify the other peers public key.
* This is mandatory for a DTLS client doing based ECDSA
* authentication. A server implementing this will request the
* client to do DTLS client authentication.
*
* @param ctx The current dtls context.
* @param session The session where the key will be used.
* @param other_pub_x x component of the public key.
* @param other_pub_y y component of the public key.
* @return @c 0 if public key matches, or less than zero on error.
* error codes:
* return dtls_alert_fatal_create(DTLS_ALERT_BAD_CERTIFICATE);
* return dtls_alert_fatal_create(DTLS_ALERT_UNSUPPORTED_CERTIFICATE);
* return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_REVOKED);
* return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_EXPIRED);
* return dtls_alert_fatal_create(DTLS_ALERT_CERTIFICATE_UNKNOWN);
* return dtls_alert_fatal_create(DTLS_ALERT_UNKNOWN_CA);
*/
int (*verify_ecdsa_key)(struct dtls_context_t *ctx,
const session_t *session,
const unsigned char *other_pub_x,
const unsigned char *other_pub_y,
size_t key_size);
#endif /* DTLS_ECC */
#ifdef DTLS_PKI
int (*get_ecdsa_certificate)(struct dtls_context_t *ctx,
const session_t *session,
const dtls_ecdsa_certificate_t **result);
int (*get_ca_info)(struct dtls_context_t *ctx,
const session_t *session,
const dtls_ca_info_t **result);
#endif /* DTLS_PKI */
} dtls_handler_t;
/** Holds global information of the DTLS engine. */
typedef struct dtls_context_t {
unsigned char cookie_secret[DTLS_COOKIE_SECRET_LENGTH];
clock_time_t cookie_secret_age; /**< the time the secret has been generated */
#ifndef WITH_CONTIKI
dtls_peer_t *peers; /**< peer hash map */
#else /* WITH_CONTIKI */
LIST_STRUCT(peers);
struct etimer retransmit_timer; /**< fires when the next packet must be sent */
// zhitao, EXPERIMENTAL
struct etimer closed_timer; /**< fires when dtls state must be set to closed */
#endif /* WITH_CONTIKI */
LIST_STRUCT(sendqueue); /**< the packets to send */
void *app; /**< application-specific data */
dtls_handler_t *h; /**< callback handlers */
unsigned char readbuf[DTLS_MAX_BUF];
} dtls_context_t;
/**
* This function initializes the tinyDTLS memory management and must
* be called first.
*/
void dtls_init();
/**
* Creates a new context object. The storage allocated for the new
* object must be released with dtls_free_context(). */
dtls_context_t *dtls_new_context(void *app_data);
/** Releases any storage that has been allocated for \p ctx. */
void dtls_free_context(dtls_context_t *ctx);
#define dtls_set_app_data(CTX,DATA) ((CTX)->app = (DATA))
#define dtls_get_app_data(CTX) ((CTX)->app)
/** Sets the callback handler object for @p ctx to @p h. */
static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) {
ctx->h = h;
}
/**
* Establishes a DTLS channel with the specified remote peer @p dst.
* This function returns @c 0 if that channel already exists, a value
* greater than zero when a new ClientHello message was sent, and
* a value less than zero on error.
*
* @param ctx The DTLS context to use.
* @param dst The remote party to connect to.
* @return A value less than zero on error, greater or equal otherwise.
*/
int dtls_connect(dtls_context_t *ctx, const session_t *dst);
/**
* Establishes a DTLS channel with the specified remote peer.
* This function returns @c 0 if that channel already exists, a value
* greater than zero when a new ClientHello message was sent, and
* a value less than zero on error.
*
* @param ctx The DTLS context to use.
* @param peer The peer object that describes the session.
* @return A value less than zero on error, greater or equal otherwise.
*/
int dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer);
/**
* Closes the DTLS connection associated with @p remote. This function
* returns zero on success, and a value less than zero on error.
*/
int dtls_close(dtls_context_t *ctx, const session_t *remote);
int dtls_renegotiate(dtls_context_t *ctx, const session_t *dst);
/**
* Writes the application data given in @p buf to the peer specified
* by @p session.
*
* @param ctx The DTLS context to use.
* @param session The remote transport address and local interface.
* @param buf The data to write.
* @param len The actual length of @p data.
*
* @return The number of bytes written or @c -1 on error.
*/
int dtls_write(struct dtls_context_t *ctx, session_t *session,
uint8 *buf, size_t len);
/**
* Checks sendqueue of given DTLS context object for any outstanding
* packets to be transmitted.
*
* @param context The DTLS context object to use.
* @param next If not NULL, @p next is filled with the timestamp
* of the next scheduled retransmission, or @c 0 when no packets are
* waiting.
*/
void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next);
#define DTLS_COOKIE_LENGTH 16
#define DTLS_CT_CHANGE_CIPHER_SPEC 20
#define DTLS_CT_ALERT 21
#define DTLS_CT_HANDSHAKE 22
#define DTLS_CT_APPLICATION_DATA 23
/** Generic header structure of the DTLS record layer. */
typedef struct __attribute__((__packed__)) {
uint8 content_type; /**< content type of the included message */
uint16 version; /**< Protocol version */
uint16 epoch; /**< counter for cipher state changes */
uint48 sequence_number; /**< sequence number */
uint16 length; /**< length of the following fragment */
/* fragment */
} dtls_record_header_t;
/* Handshake types */
#define DTLS_HT_HELLO_REQUEST 0
#define DTLS_HT_CLIENT_HELLO 1
#define DTLS_HT_SERVER_HELLO 2
#define DTLS_HT_HELLO_VERIFY_REQUEST 3
#define DTLS_HT_CERTIFICATE 11
#define DTLS_HT_SERVER_KEY_EXCHANGE 12
#define DTLS_HT_CERTIFICATE_REQUEST 13
#define DTLS_HT_SERVER_HELLO_DONE 14
#define DTLS_HT_CERTIFICATE_VERIFY 15
#define DTLS_HT_CLIENT_KEY_EXCHANGE 16
#define DTLS_HT_FINISHED 20
/* ECC Cipher Suites for TLS/DTLS RFC 4492 */
#define DTLS_NAMED_CURVE_SPECP256R1 0x0017 // 23
#define DTLS_CERT_TYPE_ECDSA_SIGN 64
#define DTLS_NONE_ECDSA 0x0003
#define DTLS_SHA1_ECDSA 0x0203
#define DTLS_SHA256_ECDSA 0x0403
#define CURVE_KEY_LENGTH 32
#define ECDH_PKEY_LENGTH 32
#define SIGNATURE_LENGTH ((2*ECDH_PKEY_LENGTH) + 2)
#define NAMED_CURVE 0x03
#ifdef DTLS_PKI
typedef struct __attribute__ ((packed)) {
uint16 signature_len; /* ANSI X9.62: length of signature */
uint8 type_r; /* DER decoding type, length, content */
uint8 len_r;
unsigned char r[CURVE_KEY_LENGTH]; /* r value of the signature */
uint8 type_s;
uint8 len_s;
unsigned char s[CURVE_KEY_LENGTH]; /* s value of the signature */
} ecdsa_signature_t ;
/** Structure of the Server/Client Key Exchange (we use only one set of ec parameters) */
typedef struct __attribute__ ((packed)) {
uint8 curve_type; /* defines the type of curve: name_curve or parameters */
uint16 curve_param_len; /* ANSI X9.62: length/number curve_params */
uint16 curve_params; /* specifies the ec domain parameters associated with the ECDH public key */
uint8 ecdh_ley_len; /* ANSI X9.62: length of signature */
unsigned char ecdh_public[2*ECDH_PKEY_LENGTH]; /* Public key of ECDH */
ecdsa_signature_t signature;
} dtls_key_exchange_t;
/** Structure of Certificate Request (we use only one set of Certificate type) */
typedef struct __attribute__ ((packed)) {
uint8 certificate_type_len; /* ANSI X9.62: length/number certificate types */
uint8 certificate_type; /* specifies permitted certificate type */
uint16 sign_hash_algo_len; /* ANSI X9.62: length/number sign_hash_algos */
uint16 sign_hash_algo; /* specifies permitted SignatureAndHashAlgorithms */
uint16 ca_len; /* ANSI X9.62: length/number ca's */
uint8 type_ca; /* DER decoding type, length, content */
uint8 len_ca;
/* Certificate_Authority */
} dtls_certificate_request_t;
#endif /* DTLS_PKI */
/** Header structure for the DTLS handshake protocol. */
typedef struct __attribute__((__packed__)) {
uint8 msg_type; /**< Type of handshake message (one of DTLS_HT_) */
uint24 length; /**< length of this message */
uint16 message_seq; /**< Message sequence number */
uint24 fragment_offset; /**< Fragment offset. */
uint24 fragment_length; /**< Fragment length. */
/* body */
} dtls_handshake_header_t;
/** Structure of the Client Hello message. */
typedef struct __attribute__((__packed__)) {
uint16 version; /**< Client version */
uint32 gmt_random; /**< GMT time of the random byte creation */
unsigned char random[28]; /**< Client random bytes */
/* session id (up to 32 bytes) */
/* cookie (up to 32 bytes) */
/* cipher suite (2 to 2^16 -1 bytes) */
/* compression method */
} dtls_client_hello_t;
/** Structure of the Hello Verify Request. */
typedef struct __attribute__((__packed__)) {
uint16 version; /**< Server version */
uint8 cookie_length; /**< Length of the included cookie */
uint8 cookie[]; /**< up to 32 bytes making up the cookie */
} dtls_hello_verify_t;
#if 0
/**
* Checks a received DTLS record for consistency and eventually decrypt,
* verify, decompress and reassemble the contained fragment for
* delivery to high-lever clients.
*
* \param state The DTLS record state for the current session.
* \param
*/
int dtls_record_read(dtls_state_t *state, uint8 *msg, int msglen);
#endif
/**
* Handles incoming data as DTLS message from given peer.
*
* @param ctx The dtls context to use.
* @param session The current session
* @param msg The received data
* @param msglen The actual length of @p msg.
* @return A value less than zero on error, zero on success.
*/
int dtls_handle_message(dtls_context_t *ctx, session_t *session,
uint8 *msg, int msglen);
/**
* Check if @p session is associated with a peer object in @p context.
* This function returns a pointer to the peer if found, NULL otherwise.
*
* @param context The DTLS context to search.
* @param session The remote address and local interface
* @return A pointer to the peer associated with @p session or NULL if
* none exists.
*/
dtls_peer_t *dtls_get_peer(const dtls_context_t *context,
const session_t *session);
#endif /* _DTLS_DTLS_H_ */
/**
* @mainpage
*
* @author Olaf Bergmann, TZI Uni Bremen
*
* This library provides a very simple datagram server with DTLS
* support. It is designed to support session multiplexing in
* single-threaded applications and thus targets specifically on
* embedded systems.
*
* @section license License
*
* This software is under the <a
* href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>.
*
* @subsection uthash UTHash
*
* This library uses <a href="http://uthash.sourceforge.net/">uthash</a> to manage
* its peers (not used for Contiki). @b uthash uses the <b>BSD revised license</b>, see
* <a href="http://uthash.sourceforge.net/license.html">http://uthash.sourceforge.net/license.html</a>.
*
* @subsection sha256 Aaron D. Gifford's SHA256 Implementation
*
* tinyDTLS provides HMAC-SHA256 with BSD-licensed code from Aaron D. Gifford,
* see <a href="http://www.aarongifford.com/">www.aarongifford.com</a>.
*
* @subsection aes Rijndael Implementation From OpenBSD
*
* The AES implementation is taken from rijndael.{c,h} contained in the crypto
* sub-system of the OpenBSD operating system. It is copyright by Vincent Rijmen, *
* Antoon Bosselaers and Paulo Barreto. See <a
* href="http://www.openbsd.org/cgi-bin/cvsweb/src/sys/crypto/rijndael.c">rijndael.c</a>
* for License info.
*
* @section download Getting the Files
*
* You can get the sources either from the <a
* href="http://sourceforge.net/projects/tinydtls/files">downloads</a> section or
* through git from the <a
* href="http://sourceforge.net/projects/tinydtls/develop">project develop page</a>.
*
* @section config Configuration
*
* Use @c configure to set up everything for a successful build. For Contiki, use the
* option @c --with-contiki.
*
* @section build Building
*
* After configuration, just type
* @code
make
* @endcode
* optionally followed by
* @code
make install
* @endcode
* The Contiki version is integrated with the Contiki build system, hence you do not
* need to invoke @c make explicitely. Just add @c tinydtls to the variable @c APPS
* in your @c Makefile.
*
* @addtogroup dtls_usage DTLS Usage
*
* @section dtls_server_example DTLS Server Example
*
* This section shows how to use the DTLS library functions to setup a
* simple secure UDP echo server. The application is responsible for the
* entire network communication and thus will look like a usual UDP
* server with socket creation and binding and a typical select-loop as
* shown below. The minimum configuration required for DTLS is the
* creation of the dtls_context_t using dtls_new_context(), and a callback
* for sending data. Received packets are read by the application and
* passed to dtls_handle_message() as shown in @ref dtls_read_cb.
* For any useful communication to happen, read and write call backs
* and a key management function should be registered as well.
*
* @code
dtls_context_t *the_context = NULL;
int fd, result;
static dtls_handler_t cb = {
.write = send_to_peer,
.read = read_from_peer,
.event = NULL,
.get_psk_key = get_psk_key
};
fd = socket(...);
if (fd < 0 || bind(fd, ...) < 0)
exit(-1);
the_context = dtls_new_context(&fd);
dtls_set_handler(the_context, &cb);
while (1) {
...initialize fd_set rfds and timeout ...
result = select(fd+1, &rfds, NULL, 0, NULL);
if (FD_ISSET(fd, &rfds))
dtls_handle_read(the_context);
}
dtls_free_context(the_context);
* @endcode
*
* @subsection dtls_read_cb The Read Callback
*
* The DTLS library expects received raw data to be passed to
* dtls_handle_message(). The application is responsible for
* filling a session_t structure with the address data of the
* remote peer as illustrated by the following example:
*
* @code
int dtls_handle_read(struct dtls_context_t *ctx) {
int *fd;
session_t session;
static uint8 buf[DTLS_MAX_BUF];
int len;
fd = dtls_get_app_data(ctx);
assert(fd);
session.size = sizeof(session.addr);
len = recvfrom(*fd, buf, sizeof(buf), 0, &session.addr.sa, &session.size);
return len < 0 ? len : dtls_handle_message(ctx, &session, buf, len);
}
* @endcode
*
* Once a new DTLS session was established and DTLS ApplicationData has been
* received, the DTLS server invokes the read callback with the MAC-verified
* cleartext data as its argument. A read callback for a simple echo server
* could look like this:
* @code
int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
return dtls_write(ctx, session, data, len);
}
* @endcode
*
* @subsection dtls_send_cb The Send Callback
*
* The callback function send_to_peer() is called whenever data must be
* sent over the network. Here, the sendto() system call is used to
* transmit data within the given session. The socket descriptor required
* by sendto() has been registered as application data when the DTLS context
* was created with dtls_new_context().
* Note that it is on the application to buffer the data when it cannot be
* sent at the time this callback is invoked. The following example thus
* is incomplete as it would have to deal with EAGAIN somehow.
* @code
int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
int fd = *(int *)dtls_get_app_data(ctx);
return sendto(fd, data, len, MSG_DONTWAIT, &session->addr.sa, session->size);
}
* @endcode
*
* @subsection dtls_get_psk_info The Key Storage
*
* When a new DTLS session is created, the library must ask the application
* for keying material. To do so, it invokes the registered call-back function
* get_psk_info() with the current context and session information as parameter.
* When the call-back function is invoked with the parameter @p type set to
* @c DTLS_PSK_IDENTITY, the result parameter @p result must be filled with
* the psk_identity_hint in case of a server, or the actual psk_identity in
* case of a client. When @p type is @c DTLS_PSK_KEY, the result parameter
* must be filled with a key for the given identity @p id. The function must
* return the number of bytes written to @p result which must not exceed
* @p result_length.
* In case of an error, the function must return a negative value that
* corresponds to a valid error code defined in alert.h.
*
* @code
int get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
const session_t *session UNUSED_PARAM,
dtls_credentials_type_t type,
const unsigned char *id, size_t id_len,
unsigned char *result, size_t result_length) {
switch (type) {
case DTLS_PSK_IDENTITY:
if (result_length < psk_id_length) {
dtls_warn("cannot set psk_identity -- buffer too small\n");
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
}
memcpy(result, psk_id, psk_id_length);
return psk_id_length;
case DTLS_PSK_KEY:
if (id_len != psk_id_length || memcmp(psk_id, id, id_len) != 0) {
dtls_warn("PSK for unknown id requested, exiting\n");
return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER);
} else if (result_length < psk_key_length) {
dtls_warn("cannot set psk -- buffer too small\n");
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
}
memcpy(result, psk_key, psk_key_length);
return psk_key_length;
default:
dtls_warn("unsupported request type: %d\n", type);
}
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
}
* @endcode
*
* @subsection dtls_events The Event Notifier
*
* Applications that want to be notified whenever the status of a DTLS session
* has changed can register an event handling function with the field @c event
* in the dtls_handler_t structure (see \ref dtls_server_example). The call-back
* function is called for alert messages and internal state changes. For alert
* messages, the argument @p level will be set to a value greater than zero, and
* @p code will indicate the notification code. For internal events, @p level
* is @c 0, and @p code a value greater than @c 255.
*
* Internal events are DTLS_EVENT_CONNECTED, @c DTLS_EVENT_CONNECT, and
* @c DTLS_EVENT_RENEGOTIATE.
*
* @code
int handle_event(struct dtls_context_t *ctx, session_t *session,
dtls_alert_level_t level, unsigned short code) {
... do something with event ...
return 0;
}
* @endcode
*
* @section dtls_client_example DTLS Client Example
*
* A DTLS client is constructed like a server but needs to actively setup
* a new session by calling dtls_connect() at some point. As this function
* usually returns before the new DTLS channel is established, the application
* must register an event handler and wait for @c DTLS_EVENT_CONNECT before
* it can send data over the DTLS channel.
*
*/
/**
* @addtogroup contiki Contiki
*
* To use tinyDTLS as Contiki application, place the source code in the directory
* @c apps/tinydtls in the Contiki source tree and invoke configure with the option
* @c --with-contiki. This will define WITH_CONTIKI in tinydtls.h and include
* @c Makefile.contiki in the main Makefile. To cross-compile for another platform
* you will need to set your host and build system accordingly. For example,
* when configuring for ARM, you would invoke
* @code
./configure --with-contiki --build=x86_64-linux-gnu --host=arm-none-eabi
* @endcode
* on an x86_64 linux host.
*
* Then, create a Contiki project with @c APPS += tinydtls in its Makefile. A sample
* server could look like this (with read_from_peer() and get_psk_key() as shown above).
*
* @code
#include "contiki.h"
#include "tinydtls.h"
#include "dtls.h"
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
int send_to_peer(struct dtls_context_t *, session_t *, uint8 *, size_t);
static struct uip_udp_conn *server_conn;
static dtls_context_t *dtls_context;
static dtls_handler_t cb = {
.write = send_to_peer,
.read = read_from_peer,
.event = NULL,
.get_psk_key = get_psk_key
};
PROCESS(server_process, "DTLS server process");
AUTOSTART_PROCESSES(&server_process);
PROCESS_THREAD(server_process, ev, data)
{
PROCESS_BEGIN();
dtls_init();
server_conn = udp_new(NULL, 0, NULL);
udp_bind(server_conn, UIP_HTONS(5684));
dtls_context = dtls_new_context(server_conn);
if (!dtls_context) {
dtls_emerg("cannot create context\n");
PROCESS_EXIT();
}
dtls_set_handler(dtls_context, &cb);
while(1) {
PROCESS_WAIT_EVENT();
if(ev == tcpip_event && uip_newdata()) {
session_t session;
uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
session.port = UIP_UDP_BUF->srcport;
session.size = sizeof(session.addr) + sizeof(session.port);
dtls_handle_message(ctx, &session, uip_appdata, uip_datalen());
}
}
PROCESS_END();
}
int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
uip_ipaddr_copy(&conn->ripaddr, &session->addr);
conn->rport = session->port;
uip_udp_packet_send(conn, data, len);
memset(&conn->ripaddr, 0, sizeof(server_conn->ripaddr));
memset(&conn->rport, 0, sizeof(conn->rport));
return len;
}
* @endcode
*/
void fdtls_set_record_header(uint8 *buf,int payload_len,uint16 epoch, uint48 seq);
int dtls_encrypt_data(dtls_context_t * ctx,dtls_peer_t *dst, uint8 *buf,size_t len,uint8 *sendbuf, size_t s_len);
void change_sequence(uint8* buf,int num);
int create_virtual_peer(dtls_context_t *ctx, session_t *sess,unsigned char *psk_id, size_t len);
int calculate_key_block_self(dtls_context_t *ctx, session_t *sess);