Imported Upstream version 1.2.0
[platform/upstream/iotivity.git] / extlibs / tinydtls / tests / dtls-client.c
1 #include "iotivity_config.h" 
2 #include "tinydtls.h" 
3
4 /* This is needed for apple */
5 #define __APPLE_USE_RFC_3542
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #ifdef HAVE_UNISTD_H
11 #include <unistd.h>
12 #endif
13 #include <ctype.h>
14 #ifdef HAVE_NETINET_IN_H
15 #include <netinet/in.h>
16 #endif
17 #include <sys/types.h>
18 #ifdef HAVE_SYS_SOCKET_H
19 #include <sys/socket.h>
20 #endif
21 #ifdef HAVE_SYS_TIME_H
22 #include <sys/time.h>
23 #endif
24 #ifdef HAVE_ARPA_INET_H
25 #include <arpa/inet.h>
26 #endif
27 #ifdef HAVE_NETDB_H
28 #include <netdb.h>
29 #endif
30 #include <signal.h>
31 #include <getopt.h>
32
33 #include "global.h"
34 #include "debug.h"
35 #include "dtls.h"
36
37 /**
38  * @struct byte_array
39  *
40  * General purpose byte array structure.
41  *
42  * Contains pointer to array of bytes and it's length.
43  */
44
45 typedef struct
46 {
47     uint8_t *data;    /**< Pointer to the byte array */
48     size_t len;      /**< Data size */
49 } byte_array;
50
51
52 /**@def BYTE_ARRAY_INITIALIZER
53  *
54  * Initializes of existing byte array pointer to \a NULL.
55  */
56 #undef BYTE_ARRAY_INITIALIZER
57 #define BYTE_ARRAY_INITIALIZER {NULL, 0}
58
59 #define DTLS_PRIVATE_KEY_SIZE        (32)
60 #define DTLS_PUBLIC_KEY_SIZE         (64)
61
62 #define DEFAULT_PORT 20220
63
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:"
69
70 #ifdef __GNUC__
71 #define UNUSED_PARAM __attribute__((unused))
72 #else
73 #define UNUSED_PARAM
74 #endif /* __GNUC__ */
75
76 static char buf[200];
77 static size_t len = 0;
78
79 typedef struct {
80   size_t length;               /* length of string */
81   unsigned char *s;            /* string data */
82 } dtls_str;
83
84 static dtls_str output_file = { 0, NULL }; /* output file name */
85
86 static dtls_context_t *dtls_context = NULL;
87 static dtls_context_t *orig_dtls_context = NULL;
88
89 #ifdef DTLS_X509
90 #define CLIENT_CRT_LEN 293
91 static const unsigned char g_client_certificate[CLIENT_CRT_LEN] = {
92         0x00, 0x01, 0x22,
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,
129         0xbc, 0x8e};
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};
136
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};
142
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};
148
149 //default CA pub key
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
155 };
156
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
162 };
163
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};
170
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};
176
177
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;
184
185 static int x509_info_from_file = 0;
186 #endif /*DTLS_X509*/
187 #ifdef DTLS_ECC
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};
193
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};
199
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};
205
206 #endif /*DTLS_ECC*/
207 #if defined(DTLS_PSK) || defined(DTLS_X509)
208 ssize_t
209 read_from_file(char *arg, unsigned char *buf, size_t max_buf_len) {
210   FILE *f;
211   ssize_t result = 0;
212
213   f = fopen(arg, "r");
214   if (f == NULL)
215     return -1;
216
217   while (!feof(f)) {
218     size_t bytes_read;
219     bytes_read = fread(buf, 1, max_buf_len, f);
220     if (ferror(f)) {
221       result = -1;
222       break;
223     }
224
225     buf += bytes_read;
226     result += bytes_read;
227     max_buf_len -= bytes_read;
228   }
229   fclose(f);
230   return result;
231 }
232 #endif /*DTLS_PSK||DTLS_X509*/
233 #ifdef DTLS_PSK
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;
243
244 /* This function is the "key store" for tinyDTLS. It is called to
245  * retrieve a key for the given identity within this particular
246  * session. */
247 static int
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) {
253
254   switch (type) {
255   case DTLS_PSK_IDENTITY:
256     if (id_len) {
257       dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
258     }
259
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);
263     }
264
265     memcpy(result, psk_client_id, psk_client_id_length);
266     return psk_client_id_length;
267   case DTLS_PSK_KEY:
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");
270     }
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);
274     }
275
276     memcpy(result, psk_key, psk_key_length);
277     return psk_key_length;
278   default:
279     dtls_warn("unsupported request type: %d\n", type);
280   }
281
282   return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
283 }
284 #endif /* DTLS_PSK */
285
286 #ifdef DTLS_ECC
287 static int
288 get_ecdsa_key(struct dtls_context_t *ctx,
289               const session_t *session,
290               const dtls_ecc_key_t **result) {
291     (void)ctx;
292     (void)session;
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
298   };
299   *result = &ecdsa_key;
300   return 0;
301 }
302
303 static int
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,
308                  size_t key_size) {
309   (void)ctx;
310   (void)session;
311   (void)other_pub_x;
312   (void)other_pub_y;
313   (void)key_size;
314   return 0;
315 }
316
317 #endif /* DTLS_ECC */
318
319 #ifdef DTLS_X509
320 static int
321 get_x509_key(struct dtls_context_t *ctx,
322           const session_t *session,
323           const dtls_ecc_key_t **result) {
324     (void)ctx;
325     (void)session;
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
331   };
332   if (x509_info_from_file)
333       ecdsa_key.priv_key = x509_client_priv;
334   *result = &ecdsa_key;
335   return 0;
336 }
337
338 static int
339 get_x509_cert(struct dtls_context_t *ctx,
340         const session_t *session,
341         const unsigned char **cert,
342         size_t *cert_size)
343 {
344     (void)ctx;
345     (void)session;
346     if (x509_info_from_file)
347     {
348         *cert = x509_client_cert;
349         *cert_size = x509_client_cert_len;
350     }
351     else
352     {
353         *cert = g_client_certificate;
354         *cert_size = CLIENT_CRT_LEN;
355     }
356
357     return 0;
358 }
359
360 int check_certificate(byte_array cert_der_code, byte_array ca_public_key)
361 {
362     (void)cert_der_code;
363     (void)ca_public_key;
364     return 0;
365 }
366
367 static int verify_x509_cert(struct dtls_context_t *ctx, const session_t *session,
368                                   const unsigned char *cert, size_t cert_size,
369                                   unsigned char *x,
370                                   size_t x_size,
371                                   unsigned char *y,
372                                   size_t y_size)
373 {
374     int ret;
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];
380     (void)ctx;
381     (void)session;
382
383     if (x509_info_from_file)
384     {
385         ca_pub_x = x509_ca_pub;
386         ca_pub_y = x509_ca_pub + DTLS_PUBLIC_KEY_SIZE/2;
387     }
388     else
389     {
390         ca_pub_x = x509_ca_pub_x;
391         ca_pub_y = x509_ca_pub_y;
392     }
393
394     cert_der_code.data = (uint8_t *)cert;
395     cert_der_code.len = cert_size;
396
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);
401
402     memcpy(x, serv_pub_key_x, x_size);
403     memcpy(y, serv_pub_key_y, y_size);
404
405     ret = (int) check_certificate(cert_der_code, ca_public_key);
406
407     return -ret;
408 }
409
410 static int is_x509_active(struct dtls_context_t *ctx)
411 {
412     (void)ctx;
413     return 0;
414 }
415
416 #endif /* DTLS_X509 */
417
418 static void
419 try_send(struct dtls_context_t *ctx, session_t *dst) {
420   int res;
421   res = dtls_write(ctx, dst, (uint8 *)buf, len);
422   if (res >= 0) {
423     memmove(buf, buf + res, len - res);
424     len -= res;
425   }
426 }
427
428 static void
429 handle_stdin() {
430   if (fgets(buf + len, sizeof(buf) - len, stdin))
431     len += strlen(buf + len);
432 }
433
434 static int
435 read_from_peer(struct dtls_context_t *ctx, 
436                session_t *session, uint8 *data, size_t len) {
437   size_t i;
438   (void)ctx;
439   (void)session;
440   for (i = 0; i < len; i++)
441     printf("%c", data[i]);
442   return 0;
443 }
444
445 static int
446 send_to_peer(struct dtls_context_t *ctx, 
447              session_t *session, uint8 *data, size_t len) {
448
449   int fd = *(int *)dtls_get_app_data(ctx);
450   return sendto(fd, data, len, MSG_DONTWAIT,
451                 &session->addr.sa, session->size);
452 }
453
454 static int
455 dtls_handle_read(struct dtls_context_t *ctx) {
456   int fd;
457   session_t session;
458 #define MAX_READ_BUF 2000
459   static uint8 buf[MAX_READ_BUF];
460   int len;
461
462   fd = *(int *)dtls_get_app_data(ctx);
463   
464   if (!fd)
465     return -1;
466
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);
471   
472   if (len < 0) {
473     perror("recvfrom");
474     return -1;
475   } else {
476     dtls_dsrv_log_addr(DTLS_LOG_DEBUG, "peer", &session);
477     dtls_debug_dump("bytes from peer", buf, len);
478   }
479
480   return dtls_handle_message(ctx, &session, buf, len);
481 }    
482
483 static void dtls_handle_signal(int sig)
484 {
485   dtls_free_context(dtls_context);
486   dtls_free_context(orig_dtls_context);
487   signal(sig, SIG_DFL);
488 #ifdef _WIN32
489   exit(sig);
490 #else
491   kill(getpid(), sig);
492 #endif
493 }
494
495 /* stolen from libcoap: */
496 static int
497 resolve_address(const char *server, struct sockaddr *dst) {
498   
499   struct addrinfo *res, *ainfo;
500   struct addrinfo hints;
501   static char addrstr[256];
502   int error;
503
504   memset(addrstr, 0, sizeof(addrstr));
505   if (server && strlen(server) > 0)
506     memcpy(addrstr, server, strlen(server));
507   else
508     memcpy(addrstr, "localhost", 9);
509
510   memset ((char *)&hints, 0, sizeof(hints));
511   hints.ai_socktype = SOCK_DGRAM;
512   hints.ai_family = AF_UNSPEC;
513
514   error = getaddrinfo(addrstr, "", &hints, &res);
515
516   if (error != 0) {
517     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
518     return error;
519   }
520
521   for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
522
523     switch (ainfo->ai_family) {
524     case AF_INET6:
525     case AF_INET:
526
527       memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
528       return ainfo->ai_addrlen;
529     default:
530       ;
531     }
532   }
533
534   freeaddrinfo(res);
535   return -1;
536 }
537
538 /*---------------------------------------------------------------------------*/
539 static void
540 usage( const char *program, const char *version) {
541   const char *p;
542
543   p = strrchr( program, '/' );
544   if ( p )
545     program = ++p;
546
547   fprintf(stderr, "%s v%s -- DTLS client implementation\n"
548           "(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
549           "usage: %s"
550 #ifdef DTLS_PSK
551           " [-i file] [-s file] [-k file]"
552 #endif /* DTLS_PSK */
553 #ifdef DTLS_X509
554           " [-x file] [-r file] [-u file]"
555 #endif /* DTLS_X509 */
556           " [-o file] [-p port] [-v num] [-c num] addr [port]\n"
557 #ifdef DTLS_PSK
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 */
562 #ifdef DTLS_X509
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);
576 }
577
578 static dtls_handler_t cb = {
579   .write = send_to_peer,
580   .read  = read_from_peer,
581   .event = NULL,
582 #ifdef DTLS_PSK
583   .get_psk_info = get_psk_info,
584 #endif /* DTLS_PSK */
585 #ifdef DTLS_ECC
586   .get_ecdsa_key = get_ecdsa_key,
587   .verify_ecdsa_key = verify_ecdsa_key,
588 #endif /* DTLS_ECC */
589 #ifdef DTLS_X509
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 */
595
596 };
597
598 #define DTLS_CLIENT_CMD_CLOSE "client:close"
599 #define DTLS_CLIENT_CMD_RENEGOTIATE "client:renegotiate"
600
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.
605  */
606 #define DTLS_CLIENT_CMD_REHANDSHAKE "client:rehandshake"
607
608 int 
609 main(int argc, char **argv) {
610   fd_set rfds, wfds;
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;
615   int fd, result;
616   int on = 1;
617   dtls_cipher_t selected_cipher = TLS_NULL_WITH_NULL_NULL;
618   dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
619   int opt, res;
620   session_t dst;
621
622   dtls_init();
623   snprintf(port_str, sizeof(port_str), "%d", port);
624
625 #ifdef DTLS_PSK
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 */
633
634   while ((opt = getopt(argc, argv, "p:o:v:c:" PSK_OPTIONS X509_OPTIONS)) != -1) {
635     switch (opt) {
636 #ifdef DTLS_PSK
637     case 'i' : {
638       ssize_t result = read_from_file(optarg, psk_client_id, PSK_ID_MAXLEN);
639       if (result < 0) {
640         dtls_warn("cannot read Client PSK identity\n");
641       } else {
642         psk_client_id_length = result;
643       }
644       break;
645     }
646     case 's' : {
647       ssize_t result = read_from_file(optarg, psk_server_id, PSK_ID_MAXLEN);
648       if (result < 0) {
649         dtls_warn("cannot read Server PSK identity\n");
650       } else {
651         psk_server_id_length = result;
652       }
653       break;
654     }
655     case 'k' : {
656       ssize_t result = read_from_file(optarg, psk_key, PSK_MAXLEN);
657       if (result < 0) {
658         dtls_warn("cannot read PSK\n");
659       } else {
660         psk_key_length = result;
661       }
662       break;
663     }
664 #endif /* DTLS_PSK */
665 #ifdef DTLS_X509
666     case 'x' :
667     {
668       ssize_t result = read_from_file(optarg, x509_client_cert, DTLS_MAX_CERT_SIZE);
669       if (result < 0)
670       {
671           dtls_warn("Cannot read Client certificate. Using default\n");
672       }
673       else
674       {
675           x509_client_cert_len = result;
676       }
677       break;
678     }
679     case 'r' :
680     {
681       ssize_t result = read_from_file(optarg, x509_client_priv, DTLS_PRIVATE_KEY_SIZE+1);
682       if (result < 0)
683       {
684           dtls_warn("Cannot read Client private key. Using default\n");
685       }
686       else
687       {
688           x509_client_priv_is_set = result;
689       }
690       break;
691     }
692     case 'u' :
693     {
694       ssize_t result = read_from_file(optarg, x509_ca_pub, DTLS_PUBLIC_KEY_SIZE+1);
695       if (result < 0)
696       {
697           dtls_warn("Cannot read CA public key. Using default\n");
698       }
699       else
700       {
701           x509_ca_pub_is_set = result;
702       }
703       break;
704     }
705 #endif /* DTLS_X509 */
706     case 'p' :
707       strncpy(port_str, optarg, NI_MAXSERV-1);
708       port_str[NI_MAXSERV - 1] = '\0';
709       break;
710     case 'o' :
711       output_file.length = strlen(optarg);
712       output_file.s = (unsigned char *)malloc(output_file.length + 1);
713
714       if (!output_file.s) {
715         dtls_crit("cannot set output file: insufficient memory\n");
716         exit(-1);
717       } else {
718         /* copy filename including trailing zero */
719         memcpy(output_file.s, optarg, output_file.length + 1);
720       }
721       break;
722     case 'v' :
723       log_level = strtol(optarg, NULL, 10);
724       break;
725     case 'c':
726       if( strcmp(optarg, "1") == 0)
727       {
728           selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256;
729           ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
730       }
731       else if( strcmp(optarg, "2") == 0)
732       {
733           selected_cipher = TLS_PSK_WITH_AES_128_CCM_8 ;
734           ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
735       }
736       else if( strcmp(optarg, "3") == 0)
737       {
738           selected_cipher = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ;
739           ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
740       }
741       else if( strcmp(optarg, "4") == 0)
742       {
743           selected_cipher = TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256;
744           ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
745       }
746       break;
747     default:
748       usage(argv[0], dtls_package_version());
749       exit(1);
750     }
751   }
752
753   dtls_set_log_level(log_level);
754
755   if (argc <= optind) {
756     usage(argv[0], dtls_package_version());
757     exit(1);
758   }
759
760 #ifdef DTLS_X509
761   if (x509_client_cert_len && x509_client_priv_is_set && x509_ca_pub_is_set)
762   {
763       x509_info_from_file = 1;
764   }
765   else if(!(x509_client_cert_len || x509_client_priv_is_set || x509_ca_pub_is_set))
766   {
767       x509_info_from_file = 0;
768   }
769   else
770   {
771       fprintf(stderr,"please set -x, -r, -u options simultaneously");
772       usage(argv[0], dtls_package_version());
773       exit(1);
774   }
775 #endif /* DTLS_X509 */
776
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);
780   if (res < 0) {
781     dtls_emerg("failed to resolve address\n");
782     exit(-1);
783   }
784   dst.size = res;
785
786   /* use port number from command line when specified or the listen
787      port, otherwise */
788   dst.addr.sin.sin_port = htons(atoi(optind < argc ? argv[optind++] : port_str));
789
790   
791   /* init socket and set it to non-blocking */
792   fd = socket(dst.addr.sa.sa_family, SOCK_DGRAM, 0);
793
794   if (fd < 0) {
795     dtls_alert("socket: %s\n", strerror(errno));
796     return 0;
797   }
798
799   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on) ) < 0) {
800     dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
801   }
802 #if 0
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));
806     goto error;
807   }
808 #endif
809   on = 1;
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));
816   }
817
818   if (signal(SIGINT, dtls_handle_signal) == SIG_ERR) {
819     dtls_alert("An error occurred while setting a signal handler.\n");
820     return EXIT_FAILURE;
821   }
822
823   dtls_context = dtls_new_context(&fd);
824   if (!dtls_context) {
825     dtls_emerg("cannot create context\n");
826     exit(-1);
827   }
828
829
830   /* select cipher suite */
831   dtls_select_cipher(dtls_context, selected_cipher);
832
833   /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */
834   dtls_enables_anon_ecdh(dtls_context, ecdh_anon_enalbe);
835
836   dtls_set_handler(dtls_context, &cb);
837
838   dtls_connect(dtls_context, &dst);
839
840   while (1) {
841     FD_ZERO(&rfds);
842     FD_ZERO(&wfds);
843
844     FD_SET(fileno(stdin), &rfds);
845     FD_SET(fd, &rfds);
846     /* FD_SET(fd, &wfds); */
847     
848     timeout.tv_sec = 5;
849     timeout.tv_usec = 0;
850     
851     result = select(fd+1, &rfds, &wfds, 0, &timeout);
852     
853     if (result < 0) {           /* error */
854       if (errno != EINTR)
855         perror("select");
856     } else if (result == 0) {   /* timeout */
857     } else {                    /* ok */
858       if (FD_ISSET(fd, &wfds))
859         /* FIXME */;
860       else if (FD_ISSET(fd, &rfds))
861         dtls_handle_read(dtls_context);
862       else if (FD_ISSET(fileno(stdin), &rfds))
863         handle_stdin();
864     }
865
866     if (len) {
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);
871         len = 0;
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);
876         len = 0;
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).
883            */
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);
887           if (!dtls_context) {
888             dtls_emerg("cannot create context\n");
889             exit(-1);
890           }
891           dtls_set_handler(dtls_context, &cb);
892           dtls_connect(dtls_context, &dst);
893         }
894         len = 0;
895       } else {
896         try_send(dtls_context, &dst);
897       }
898     }
899   }
900   
901   dtls_free_context(dtls_context);
902   dtls_free_context(orig_dtls_context);
903   exit(0);
904 }
905