1 #include "iotivity_config.h"
4 /* This is needed for apple */
5 #define __APPLE_USE_RFC_3542
14 #ifdef HAVE_NETINET_IN_H
15 #include <netinet/in.h>
17 #include <sys/types.h>
18 #ifdef HAVE_SYS_SOCKET_H
19 #include <sys/socket.h>
21 #ifdef HAVE_SYS_TIME_H
24 #ifdef HAVE_ARPA_INET_H
25 #include <arpa/inet.h>
40 * General purpose byte array structure.
42 * Contains pointer to array of bytes and it's length.
47 uint8_t *data; /**< Pointer to the byte array */
48 size_t len; /**< Data size */
52 /**@def BYTE_ARRAY_INITIALIZER
54 * Initializes of existing byte array pointer to \a NULL.
56 #undef BYTE_ARRAY_INITIALIZER
57 #define BYTE_ARRAY_INITIALIZER {NULL, 0}
59 #define DTLS_PRIVATE_KEY_SIZE (32)
60 #define DTLS_PUBLIC_KEY_SIZE (64)
62 #define DEFAULT_PORT 20220
64 #define PSK_CLIENT_IDENTITY "Client_identity"
65 #define PSK_SERVER_IDENTITY "Server_identity"
66 #define PSK_DEFAULT_KEY "secretPSK"
67 #define PSK_OPTIONS "i:s:k:"
68 #define X509_OPTIONS "x:r:u:"
71 #define UNUSED_PARAM __attribute__((unused))
77 static size_t len = 0;
80 size_t length; /* length of string */
81 unsigned char *s; /* string data */
84 static dtls_str output_file = { 0, NULL }; /* output file name */
86 static dtls_context_t *dtls_context = NULL;
87 static dtls_context_t *orig_dtls_context = NULL;
90 #define CLIENT_CRT_LEN 293
91 static const unsigned char g_client_certificate[CLIENT_CRT_LEN] = {
93 0x30, 0x82, 0x01, 0x1e, 0x30, 0x81, 0xc4, 0xa0,
94 0x03, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x38,
95 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
96 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x17,
97 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
98 0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
99 0x20, 0x49, 0x53, 0x53, 0x55, 0x45, 0x52, 0x30,
100 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x31, 0x30,
101 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
102 0x17, 0x0d, 0x34, 0x39, 0x30, 0x31, 0x30, 0x31,
103 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
104 0x17, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
105 0x04, 0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61,
106 0x6c, 0x20, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54,
107 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
108 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
109 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
110 0x42, 0x00, 0x04, 0xe3, 0xd1, 0x67, 0x1e, 0xdc,
111 0x46, 0xf4, 0x19, 0x50, 0x15, 0x2e, 0x3a, 0x2f,
112 0xd8, 0x68, 0x6b, 0x37, 0x32, 0x84, 0x9e, 0x83,
113 0x81, 0xbf, 0x25, 0x5d, 0xbb, 0x18, 0x07, 0x3c,
114 0xbd, 0xf3, 0xab, 0xd3, 0xbf, 0x53, 0x59, 0xc9,
115 0x1e, 0xce, 0x5b, 0x39, 0x6a, 0xe5, 0x60, 0xf3,
116 0x70, 0xdb, 0x66, 0xb6, 0x80, 0xcb, 0x65, 0x0b,
117 0x35, 0x2a, 0x62, 0x44, 0x89, 0x63, 0x64, 0x6f,
118 0x6f, 0xbd, 0xf0, 0x30, 0x0c, 0x06, 0x08, 0x2a,
119 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05,
120 0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20,
121 0x60, 0xdc, 0x45, 0x77, 0x7d, 0xcb, 0xc3, 0xb4,
122 0xba, 0x60, 0x5a, 0x2e, 0xe5, 0x4e, 0x19, 0x8b,
123 0x48, 0x8a, 0x87, 0xd4, 0x66, 0xb4, 0x1a, 0x86,
124 0x23, 0x67, 0xb8, 0xb6, 0x50, 0xfe, 0x4d, 0xde,
125 0x02, 0x20, 0x60, 0x68, 0x46, 0xff, 0x74, 0x11,
126 0xfb, 0x36, 0x13, 0xf4, 0xa7, 0x3d, 0xb7, 0x35,
127 0x79, 0x23, 0x29, 0x14, 0x6a, 0x28, 0x09, 0xff,
128 0x8c, 0x19, 0x26, 0xe3, 0x41, 0xc8, 0xe4, 0x13,
130 //default client's key pair
131 static const unsigned char x509_priv_key[] = {
132 0xf9, 0x42, 0xb4, 0x16, 0x89, 0x10, 0xf4, 0x07,
133 0x99, 0xb2, 0xe2, 0x9a, 0xed, 0xd4, 0x39, 0xb8,
134 0xca, 0xd4, 0x9d, 0x76, 0x11, 0x43, 0x3a, 0xac,
135 0x14, 0xba, 0x17, 0x9d, 0x3e, 0xbb, 0xbf, 0xbc};
137 static const unsigned char x509_pub_key_x[] = {
138 0xe3, 0xd1, 0x67, 0x1e, 0xdc, 0x46, 0xf4, 0x19,
139 0x50, 0x15, 0x2e, 0x3a, 0x2f, 0xd8, 0x68, 0x6b,
140 0x37, 0x32, 0x84, 0x9e, 0x83, 0x81, 0xbf, 0x25,
141 0x5d, 0xbb, 0x18, 0x07, 0x3c, 0xbd, 0xf3, 0xab};
143 static const unsigned char x509_pub_key_y[] = {
144 0xd3, 0xbf, 0x53, 0x59, 0xc9, 0x1e, 0xce, 0x5b,
145 0x39, 0x6a, 0xe5, 0x60, 0xf3, 0x70, 0xdb, 0x66,
146 0xb6, 0x80, 0xcb, 0x65, 0x0b, 0x35, 0x2a, 0x62,
147 0x44, 0x89, 0x63, 0x64, 0x6f, 0x6f, 0xbd, 0xf0};
150 static const unsigned char x509_ca_pub_x[] = {
151 0x57, 0x94, 0x7f, 0x98, 0x7a, 0x02, 0x67, 0x09,
152 0x25, 0xc1, 0xcb, 0x5a, 0xf5, 0x46, 0xfb, 0xad,
153 0xf7, 0x68, 0x94, 0x8c, 0xa7, 0xe3, 0xf0, 0x5b,
154 0xc3, 0x6b, 0x5c, 0x9b, 0xd3, 0x7d, 0x74, 0x12
157 static const unsigned char x509_ca_pub_y[] = {
158 0xce, 0x68, 0xbc, 0x55, 0xf5, 0xf8, 0x1b, 0x3d,
159 0xef, 0xed, 0x1f, 0x2b, 0xd2, 0x69, 0x5d, 0xcf,
160 0x79, 0x16, 0xa6, 0xbd, 0x97, 0x96, 0x27, 0x60,
161 0x5d, 0xd1, 0xb7, 0x93, 0xa2, 0x4a, 0x62, 0x4d
164 //default server's key pair
165 static const unsigned char serv_pub_key_x[] = {
166 0x07, 0x88, 0x10, 0xdc, 0x62, 0xd7, 0xe6, 0x9b,
167 0x7c, 0xad, 0x6e, 0x78, 0xb0, 0x5f, 0x9a, 0x00,
168 0x11, 0x74, 0x2c, 0x8b, 0xaf, 0x09, 0x65, 0x7c,
169 0x86, 0x8e, 0x55, 0xcb, 0x39, 0x55, 0x72, 0xc6};
171 static const unsigned char serv_pub_key_y[] = {
172 0x65, 0x71, 0xcd, 0x03, 0xdc, 0x2a, 0x4f, 0x46,
173 0x5b, 0x14, 0xc8, 0x27, 0x74, 0xab, 0xf4, 0x1f,
174 0xc1, 0x35, 0x0d, 0x42, 0xbc, 0xc2, 0x9f, 0xb5,
175 0xc1, 0x79, 0xb6, 0x8b, 0xca, 0xdb, 0xff, 0x82};
178 static unsigned char x509_client_cert[DTLS_MAX_CERT_SIZE];
179 static size_t x509_client_cert_len = 0;
180 static unsigned char x509_client_priv[DTLS_PRIVATE_KEY_SIZE+1];
181 static size_t x509_client_priv_is_set = 0;
182 static unsigned char x509_ca_pub[DTLS_PUBLIC_KEY_SIZE+1];
183 static size_t x509_ca_pub_is_set = 0;
185 static int x509_info_from_file = 0;
188 static const unsigned char ecdsa_priv_key[] = {
189 0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
190 0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
191 0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
192 0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA};
194 static const unsigned char ecdsa_pub_key_x[] = {
195 0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
196 0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
197 0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
198 0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52};
200 static const unsigned char ecdsa_pub_key_y[] = {
201 0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
202 0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
203 0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
204 0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29};
207 #if defined(DTLS_PSK) || defined(DTLS_X509)
209 read_from_file(char *arg, unsigned char *buf, size_t max_buf_len) {
219 bytes_read = fread(buf, 1, max_buf_len, f);
226 result += bytes_read;
227 max_buf_len -= bytes_read;
232 #endif /*DTLS_PSK||DTLS_X509*/
234 /* The PSK information for DTLS */
235 #define PSK_ID_MAXLEN 256
236 #define PSK_MAXLEN 256
237 static unsigned char psk_client_id[PSK_ID_MAXLEN];
238 static size_t psk_client_id_length = 0;
239 static unsigned char psk_server_id[PSK_ID_MAXLEN];
240 static size_t psk_server_id_length = 0;
241 static unsigned char psk_key[PSK_MAXLEN];
242 static size_t psk_key_length = 0;
244 /* This function is the "key store" for tinyDTLS. It is called to
245 * retrieve a key for the given identity within this particular
248 get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
249 const session_t *session UNUSED_PARAM,
250 dtls_credentials_type_t type,
251 const unsigned char *id, size_t id_len,
252 unsigned char *result, size_t result_length) {
255 case DTLS_PSK_IDENTITY:
257 dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
260 if (result_length < psk_client_id_length) {
261 dtls_warn("cannot set psk_identity -- buffer too small\n");
262 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
265 memcpy(result, psk_client_id, psk_client_id_length);
266 return psk_client_id_length;
268 if (id_len != psk_server_id_length || memcmp(psk_server_id, id, id_len) != 0) {
269 dtls_debug("PSK for unknown id requested\n");
271 if (result_length < psk_key_length) {
272 dtls_warn("cannot set psk -- buffer too small\n");
273 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
276 memcpy(result, psk_key, psk_key_length);
277 return psk_key_length;
279 dtls_warn("unsupported request type: %d\n", type);
282 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
284 #endif /* DTLS_PSK */
288 get_ecdsa_key(struct dtls_context_t *ctx,
289 const session_t *session,
290 const dtls_ecc_key_t **result) {
293 static const dtls_ecc_key_t ecdsa_key = {
294 .curve = DTLS_ECDH_CURVE_SECP256R1,
295 .priv_key = ecdsa_priv_key,
296 .pub_key_x = ecdsa_pub_key_x,
297 .pub_key_y = ecdsa_pub_key_y
299 *result = &ecdsa_key;
304 verify_ecdsa_key(struct dtls_context_t *ctx,
305 const session_t *session,
306 const unsigned char *other_pub_x,
307 const unsigned char *other_pub_y,
317 #endif /* DTLS_ECC */
321 get_x509_key(struct dtls_context_t *ctx,
322 const session_t *session,
323 const dtls_ecc_key_t **result) {
326 static dtls_ecc_key_t ecdsa_key = {
327 .curve = DTLS_ECDH_CURVE_SECP256R1,
328 .priv_key = x509_priv_key,
329 .pub_key_x = x509_pub_key_x,
330 .pub_key_y = x509_pub_key_y
332 if (x509_info_from_file)
333 ecdsa_key.priv_key = x509_client_priv;
334 *result = &ecdsa_key;
339 get_x509_cert(struct dtls_context_t *ctx,
340 const session_t *session,
341 const unsigned char **cert,
346 if (x509_info_from_file)
348 *cert = x509_client_cert;
349 *cert_size = x509_client_cert_len;
353 *cert = g_client_certificate;
354 *cert_size = CLIENT_CRT_LEN;
360 int check_certificate(byte_array cert_der_code, byte_array ca_public_key)
367 static int verify_x509_cert(struct dtls_context_t *ctx, const session_t *session,
368 const unsigned char *cert, size_t cert_size,
375 const unsigned char *ca_pub_x;
376 const unsigned char *ca_pub_y;
377 byte_array cert_der_code = BYTE_ARRAY_INITIALIZER;
378 byte_array ca_public_key = BYTE_ARRAY_INITIALIZER;
379 unsigned char ca_pub_key[DTLS_PUBLIC_KEY_SIZE];
383 if (x509_info_from_file)
385 ca_pub_x = x509_ca_pub;
386 ca_pub_y = x509_ca_pub + DTLS_PUBLIC_KEY_SIZE/2;
390 ca_pub_x = x509_ca_pub_x;
391 ca_pub_y = x509_ca_pub_y;
394 cert_der_code.data = (uint8_t *)cert;
395 cert_der_code.len = cert_size;
397 ca_public_key.len = DTLS_PUBLIC_KEY_SIZE;
398 ca_public_key.data = ca_pub_key;
399 memcpy(ca_public_key.data, ca_pub_x, DTLS_PUBLIC_KEY_SIZE/2);
400 memcpy(ca_public_key.data + DTLS_PUBLIC_KEY_SIZE/2, ca_pub_y, DTLS_PUBLIC_KEY_SIZE/2);
402 memcpy(x, serv_pub_key_x, x_size);
403 memcpy(y, serv_pub_key_y, y_size);
405 ret = (int) check_certificate(cert_der_code, ca_public_key);
410 static int is_x509_active(struct dtls_context_t *ctx)
416 #endif /* DTLS_X509 */
419 try_send(struct dtls_context_t *ctx, session_t *dst) {
421 res = dtls_write(ctx, dst, (uint8 *)buf, len);
423 memmove(buf, buf + res, len - res);
430 if (fgets(buf + len, sizeof(buf) - len, stdin))
431 len += strlen(buf + len);
435 read_from_peer(struct dtls_context_t *ctx,
436 session_t *session, uint8 *data, size_t len) {
440 for (i = 0; i < len; i++)
441 printf("%c", data[i]);
446 send_to_peer(struct dtls_context_t *ctx,
447 session_t *session, uint8 *data, size_t len) {
449 int fd = *(int *)dtls_get_app_data(ctx);
450 return sendto(fd, data, len, MSG_DONTWAIT,
451 &session->addr.sa, session->size);
455 dtls_handle_read(struct dtls_context_t *ctx) {
458 #define MAX_READ_BUF 2000
459 static uint8 buf[MAX_READ_BUF];
462 fd = *(int *)dtls_get_app_data(ctx);
467 memset(&session, 0, sizeof(session_t));
468 session.size = sizeof(session.addr);
469 len = recvfrom(fd, buf, MAX_READ_BUF, 0,
470 &session.addr.sa, &session.size);
476 dtls_dsrv_log_addr(DTLS_LOG_DEBUG, "peer", &session);
477 dtls_debug_dump("bytes from peer", buf, len);
480 return dtls_handle_message(ctx, &session, buf, len);
483 static void dtls_handle_signal(int sig)
485 dtls_free_context(dtls_context);
486 dtls_free_context(orig_dtls_context);
487 signal(sig, SIG_DFL);
495 /* stolen from libcoap: */
497 resolve_address(const char *server, struct sockaddr *dst) {
499 struct addrinfo *res, *ainfo;
500 struct addrinfo hints;
501 static char addrstr[256];
504 memset(addrstr, 0, sizeof(addrstr));
505 if (server && strlen(server) > 0)
506 memcpy(addrstr, server, strlen(server));
508 memcpy(addrstr, "localhost", 9);
510 memset ((char *)&hints, 0, sizeof(hints));
511 hints.ai_socktype = SOCK_DGRAM;
512 hints.ai_family = AF_UNSPEC;
514 error = getaddrinfo(addrstr, "", &hints, &res);
517 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
521 for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
523 switch (ainfo->ai_family) {
527 memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
528 return ainfo->ai_addrlen;
538 /*---------------------------------------------------------------------------*/
540 usage( const char *program, const char *version) {
543 p = strrchr( program, '/' );
547 fprintf(stderr, "%s v%s -- DTLS client implementation\n"
548 "(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
551 " [-i file] [-s file] [-k file]"
552 #endif /* DTLS_PSK */
554 " [-x file] [-r file] [-u file]"
555 #endif /* DTLS_X509 */
556 " [-o file] [-p port] [-v num] [-c num] addr [port]\n"
558 "\t-i file\t\tread PSK Client identity from file\n"
559 "\t-s file\t\tread PSK Server identity from file\n"
560 "\t-k file\t\tread pre-shared key from file\n"
561 #endif /* DTLS_PSK */
563 "\t-x file\tread Client certificate from file\n"
564 "\t-r file\tread Client private key from file\n"
565 "\t-u file\tread CA public key from file\n"
566 #endif /* DTLS_X509 */
567 "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n"
568 "\t-p port\t\tlisten on specified port (default is %d)\n"
569 "\t-v num\t\tverbosity level (default: 3)\n"
570 "\t-c num\t\tcipher suite (default: 1)\n"
571 "\t\t\t1: TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 \n"
572 "\t\t\t2: TLS_PSK_WITH_AES_128_CCM_8\n"
573 "\t\t\t3: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n"
574 "\t\t\t4: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256\n",
575 program, version, program, DEFAULT_PORT);
578 static dtls_handler_t cb = {
579 .write = send_to_peer,
580 .read = read_from_peer,
583 .get_psk_info = get_psk_info,
584 #endif /* DTLS_PSK */
586 .get_ecdsa_key = get_ecdsa_key,
587 .verify_ecdsa_key = verify_ecdsa_key,
588 #endif /* DTLS_ECC */
590 .get_x509_key = get_x509_key,
591 .verify_x509_cert = verify_x509_cert,
592 .get_x509_cert = get_x509_cert,
593 .is_x509_active = is_x509_active,
594 #endif /* DTLS_X509 */
598 #define DTLS_CLIENT_CMD_CLOSE "client:close"
599 #define DTLS_CLIENT_CMD_RENEGOTIATE "client:renegotiate"
601 /* As per RFC 6347 section 4.2.8, DTLS Server should support requests
602 * from clients who have silently abandoned the existing association
603 * and initiated a new handshake request by sending a ClientHello.
604 * Below command tests this feature.
606 #define DTLS_CLIENT_CMD_REHANDSHAKE "client:rehandshake"
609 main(int argc, char **argv) {
611 struct timeval timeout;
612 unsigned short port = DEFAULT_PORT;
613 char port_str[NI_MAXSERV] = "0";
614 log_t log_level = DTLS_LOG_WARN;
617 dtls_cipher_t selected_cipher = TLS_NULL_WITH_NULL_NULL;
618 dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
623 snprintf(port_str, sizeof(port_str), "%d", port);
626 psk_client_id_length = strlen(PSK_CLIENT_IDENTITY);
627 psk_server_id_length = strlen(PSK_SERVER_IDENTITY);
628 psk_key_length = strlen(PSK_DEFAULT_KEY);
629 memcpy(psk_client_id, PSK_CLIENT_IDENTITY, psk_client_id_length);
630 memcpy(psk_server_id, PSK_SERVER_IDENTITY, psk_server_id_length);
631 memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length);
632 #endif /* DTLS_PSK */
634 while ((opt = getopt(argc, argv, "p:o:v:c:" PSK_OPTIONS X509_OPTIONS)) != -1) {
638 ssize_t result = read_from_file(optarg, psk_client_id, PSK_ID_MAXLEN);
640 dtls_warn("cannot read Client PSK identity\n");
642 psk_client_id_length = result;
647 ssize_t result = read_from_file(optarg, psk_server_id, PSK_ID_MAXLEN);
649 dtls_warn("cannot read Server PSK identity\n");
651 psk_server_id_length = result;
656 ssize_t result = read_from_file(optarg, psk_key, PSK_MAXLEN);
658 dtls_warn("cannot read PSK\n");
660 psk_key_length = result;
664 #endif /* DTLS_PSK */
668 ssize_t result = read_from_file(optarg, x509_client_cert, DTLS_MAX_CERT_SIZE);
671 dtls_warn("Cannot read Client certificate. Using default\n");
675 x509_client_cert_len = result;
681 ssize_t result = read_from_file(optarg, x509_client_priv, DTLS_PRIVATE_KEY_SIZE+1);
684 dtls_warn("Cannot read Client private key. Using default\n");
688 x509_client_priv_is_set = result;
694 ssize_t result = read_from_file(optarg, x509_ca_pub, DTLS_PUBLIC_KEY_SIZE+1);
697 dtls_warn("Cannot read CA public key. Using default\n");
701 x509_ca_pub_is_set = result;
705 #endif /* DTLS_X509 */
707 strncpy(port_str, optarg, NI_MAXSERV-1);
708 port_str[NI_MAXSERV - 1] = '\0';
711 output_file.length = strlen(optarg);
712 output_file.s = (unsigned char *)malloc(output_file.length + 1);
714 if (!output_file.s) {
715 dtls_crit("cannot set output file: insufficient memory\n");
718 /* copy filename including trailing zero */
719 memcpy(output_file.s, optarg, output_file.length + 1);
723 log_level = strtol(optarg, NULL, 10);
726 if( strcmp(optarg, "1") == 0)
728 selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256;
729 ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
731 else if( strcmp(optarg, "2") == 0)
733 selected_cipher = TLS_PSK_WITH_AES_128_CCM_8 ;
734 ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
736 else if( strcmp(optarg, "3") == 0)
738 selected_cipher = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ;
739 ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
741 else if( strcmp(optarg, "4") == 0)
743 selected_cipher = TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256;
744 ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
748 usage(argv[0], dtls_package_version());
753 dtls_set_log_level(log_level);
755 if (argc <= optind) {
756 usage(argv[0], dtls_package_version());
761 if (x509_client_cert_len && x509_client_priv_is_set && x509_ca_pub_is_set)
763 x509_info_from_file = 1;
765 else if(!(x509_client_cert_len || x509_client_priv_is_set || x509_ca_pub_is_set))
767 x509_info_from_file = 0;
771 fprintf(stderr,"please set -x, -r, -u options simultaneously");
772 usage(argv[0], dtls_package_version());
775 #endif /* DTLS_X509 */
777 memset(&dst, 0, sizeof(session_t));
778 /* resolve destination address where server should be sent */
779 res = resolve_address(argv[optind++], &dst.addr.sa);
781 dtls_emerg("failed to resolve address\n");
786 /* use port number from command line when specified or the listen
788 dst.addr.sin.sin_port = htons(atoi(optind < argc ? argv[optind++] : port_str));
791 /* init socket and set it to non-blocking */
792 fd = socket(dst.addr.sa.sa_family, SOCK_DGRAM, 0);
795 dtls_alert("socket: %s\n", strerror(errno));
799 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on) ) < 0) {
800 dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
803 flags = fcntl(fd, F_GETFL, 0);
804 if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
805 dtls_alert("fcntl: %s\n", strerror(errno));
810 #ifdef IPV6_RECVPKTINFO
811 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, OPTVAL_T(&on), sizeof(on) ) < 0) {
812 #else /* IPV6_RECVPKTINFO */
813 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, OPTVAL_T(&on), sizeof(on) ) < 0) {
814 #endif /* IPV6_RECVPKTINFO */
815 dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
818 if (signal(SIGINT, dtls_handle_signal) == SIG_ERR) {
819 dtls_alert("An error occurred while setting a signal handler.\n");
823 dtls_context = dtls_new_context(&fd);
825 dtls_emerg("cannot create context\n");
830 /* select cipher suite */
831 dtls_select_cipher(dtls_context, selected_cipher);
833 /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */
834 dtls_enables_anon_ecdh(dtls_context, ecdh_anon_enalbe);
836 dtls_set_handler(dtls_context, &cb);
838 dtls_connect(dtls_context, &dst);
844 FD_SET(fileno(stdin), &rfds);
846 /* FD_SET(fd, &wfds); */
851 result = select(fd+1, &rfds, &wfds, 0, &timeout);
853 if (result < 0) { /* error */
856 } else if (result == 0) { /* timeout */
858 if (FD_ISSET(fd, &wfds))
860 else if (FD_ISSET(fd, &rfds))
861 dtls_handle_read(dtls_context);
862 else if (FD_ISSET(fileno(stdin), &rfds))
867 if (len >= strlen(DTLS_CLIENT_CMD_CLOSE) &&
868 !memcmp(buf, DTLS_CLIENT_CMD_CLOSE, strlen(DTLS_CLIENT_CMD_CLOSE))) {
869 printf("client: closing connection\n");
870 dtls_close(dtls_context, &dst);
872 } else if (len >= strlen(DTLS_CLIENT_CMD_RENEGOTIATE) &&
873 !memcmp(buf, DTLS_CLIENT_CMD_RENEGOTIATE, strlen(DTLS_CLIENT_CMD_RENEGOTIATE))) {
874 printf("client: renegotiate connection\n");
875 dtls_renegotiate(dtls_context, &dst);
877 } else if (len >= strlen(DTLS_CLIENT_CMD_REHANDSHAKE) &&
878 !memcmp(buf, DTLS_CLIENT_CMD_REHANDSHAKE, strlen(DTLS_CLIENT_CMD_REHANDSHAKE))) {
879 printf("client: rehandshake connection\n");
880 if (orig_dtls_context == NULL) {
881 /* Cache the current context. We cannot free the current context as it will notify
882 * the Server to close the connection (which we do not want).
884 orig_dtls_context = dtls_context;
885 /* Now, Create a new context and attempt to initiate a handshake. */
886 dtls_context = dtls_new_context(&fd);
888 dtls_emerg("cannot create context\n");
891 dtls_set_handler(dtls_context, &cb);
892 dtls_connect(dtls_context, &dst);
896 try_send(dtls_context, &dst);
901 dtls_free_context(dtls_context);
902 dtls_free_context(orig_dtls_context);