Imported Upstream version 1.0.1
[platform/upstream/iotivity.git] / extlibs / tinydtls / tests / dtls-client.c
1 #include "tinydtls.h" 
2
3 /* This is needed for apple */
4 #define __APPLE_USE_RFC_3542
5
6 #include <stdio.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <ctype.h>
11 #include <netinet/in.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/time.h>
15 #include <arpa/inet.h>
16 #include <netdb.h>
17 #include <signal.h>
18
19 #include "global.h"
20 #include "debug.h"
21 #include "dtls.h"
22
23 /**
24  * @struct byte_array
25  *
26  * General purpose byte array structure.
27  *
28  * Contains pointer to array of bytes and it's length.
29  */
30
31 typedef struct
32 {
33     uint8_t *data;    /**< Pointer to the byte array */
34     size_t len;      /**< Data size */
35 } byte_array;
36
37
38 /**@def BYTE_ARRAY_INITIALIZER
39  *
40  * Initializes of existing byte array pointer to \a NULL.
41  */
42 #undef BYTE_ARRAY_INITIALIZER
43 #define BYTE_ARRAY_INITIALIZER {NULL, 0}
44
45 #define DTLS_PRIVATE_KEY_SIZE        (32)
46 #define DTLS_PUBLIC_KEY_SIZE         (64)
47
48 #define DEFAULT_PORT 20220
49
50 #define PSK_CLIENT_IDENTITY  "Client_identity"
51 #define PSK_SERVER_IDENTITY  "Server_identity"
52 #define PSK_DEFAULT_KEY      "secretPSK"
53 #define PSK_OPTIONS          "i:s:k:"
54 #define X509_OPTIONS         "x:r:u:"
55
56 #ifdef __GNUC__
57 #define UNUSED_PARAM __attribute__((unused))
58 #else
59 #define UNUSED_PARAM
60 #endif /* __GNUC__ */
61
62 static char buf[200];
63 static size_t len = 0;
64
65 typedef struct {
66   size_t length;               /* length of string */
67   unsigned char *s;            /* string data */
68 } dtls_str;
69
70 static dtls_str output_file = { 0, NULL }; /* output file name */
71
72 static dtls_context_t *dtls_context = NULL;
73 static dtls_context_t *orig_dtls_context = NULL;
74
75 #ifdef DTLS_X509
76 #define CLIENT_CRT_LEN 293
77 static const unsigned char g_client_certificate[CLIENT_CRT_LEN] = {
78         0x00, 0x01, 0x22,
79         0x30, 0x82, 0x01, 0x1e, 0x30, 0x81, 0xc4, 0xa0,
80         0x03, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x38,
81         0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
82         0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x17,
83         0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
84         0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
85         0x20, 0x49, 0x53, 0x53, 0x55, 0x45, 0x52, 0x30,
86         0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x31, 0x30,
87         0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
88         0x17, 0x0d, 0x34, 0x39, 0x30, 0x31, 0x30, 0x31,
89         0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
90         0x17, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
91         0x04, 0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61,
92         0x6c, 0x20, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54,
93         0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
94         0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
95         0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
96         0x42, 0x00, 0x04, 0xe3, 0xd1, 0x67, 0x1e, 0xdc,
97         0x46, 0xf4, 0x19, 0x50, 0x15, 0x2e, 0x3a, 0x2f,
98         0xd8, 0x68, 0x6b, 0x37, 0x32, 0x84, 0x9e, 0x83,
99         0x81, 0xbf, 0x25, 0x5d, 0xbb, 0x18, 0x07, 0x3c,
100         0xbd, 0xf3, 0xab, 0xd3, 0xbf, 0x53, 0x59, 0xc9,
101         0x1e, 0xce, 0x5b, 0x39, 0x6a, 0xe5, 0x60, 0xf3,
102         0x70, 0xdb, 0x66, 0xb6, 0x80, 0xcb, 0x65, 0x0b,
103         0x35, 0x2a, 0x62, 0x44, 0x89, 0x63, 0x64, 0x6f,
104         0x6f, 0xbd, 0xf0, 0x30, 0x0c, 0x06, 0x08, 0x2a,
105         0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05,
106         0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20,
107         0x60, 0xdc, 0x45, 0x77, 0x7d, 0xcb, 0xc3, 0xb4,
108         0xba, 0x60, 0x5a, 0x2e, 0xe5, 0x4e, 0x19, 0x8b,
109         0x48, 0x8a, 0x87, 0xd4, 0x66, 0xb4, 0x1a, 0x86,
110         0x23, 0x67, 0xb8, 0xb6, 0x50, 0xfe, 0x4d, 0xde,
111         0x02, 0x20, 0x60, 0x68, 0x46, 0xff, 0x74, 0x11,
112         0xfb, 0x36, 0x13, 0xf4, 0xa7, 0x3d, 0xb7, 0x35,
113         0x79, 0x23, 0x29, 0x14, 0x6a, 0x28, 0x09, 0xff,
114         0x8c, 0x19, 0x26, 0xe3, 0x41, 0xc8, 0xe4, 0x13,
115         0xbc, 0x8e};
116 //default client's key pair
117 static const unsigned char x509_priv_key[] = {
118         0xf9, 0x42, 0xb4, 0x16, 0x89, 0x10, 0xf4, 0x07,
119         0x99, 0xb2, 0xe2, 0x9a, 0xed, 0xd4, 0x39, 0xb8,
120         0xca, 0xd4, 0x9d, 0x76, 0x11, 0x43, 0x3a, 0xac,
121         0x14, 0xba, 0x17, 0x9d, 0x3e, 0xbb, 0xbf, 0xbc};
122
123 static const unsigned char x509_pub_key_x[] = {
124         0xe3, 0xd1, 0x67, 0x1e, 0xdc, 0x46, 0xf4, 0x19,
125         0x50, 0x15, 0x2e, 0x3a, 0x2f, 0xd8, 0x68, 0x6b,
126         0x37, 0x32, 0x84, 0x9e, 0x83, 0x81, 0xbf, 0x25,
127         0x5d, 0xbb, 0x18, 0x07, 0x3c, 0xbd, 0xf3, 0xab};
128
129 static const unsigned char x509_pub_key_y[] = {
130         0xd3, 0xbf, 0x53, 0x59, 0xc9, 0x1e, 0xce, 0x5b,
131         0x39, 0x6a, 0xe5, 0x60, 0xf3, 0x70, 0xdb, 0x66,
132         0xb6, 0x80, 0xcb, 0x65, 0x0b, 0x35, 0x2a, 0x62,
133         0x44, 0x89, 0x63, 0x64, 0x6f, 0x6f, 0xbd, 0xf0};
134
135 //default CA pub key
136 static const unsigned char x509_ca_pub_x[] = {
137         0x57, 0x94, 0x7f, 0x98, 0x7a, 0x02, 0x67, 0x09,
138         0x25, 0xc1, 0xcb, 0x5a, 0xf5, 0x46, 0xfb, 0xad,
139         0xf7, 0x68, 0x94, 0x8c, 0xa7, 0xe3, 0xf0, 0x5b,
140         0xc3, 0x6b, 0x5c, 0x9b, 0xd3, 0x7d, 0x74, 0x12
141 };
142
143 static const unsigned char x509_ca_pub_y[] = {
144         0xce, 0x68, 0xbc, 0x55, 0xf5, 0xf8, 0x1b, 0x3d,
145         0xef, 0xed, 0x1f, 0x2b, 0xd2, 0x69, 0x5d, 0xcf,
146         0x79, 0x16, 0xa6, 0xbd, 0x97, 0x96, 0x27, 0x60,
147         0x5d, 0xd1, 0xb7, 0x93, 0xa2, 0x4a, 0x62, 0x4d
148 };
149
150 //default server's key pair
151 static const unsigned char serv_pub_key_x[] = {
152         0x07, 0x88, 0x10, 0xdc, 0x62, 0xd7, 0xe6, 0x9b,
153         0x7c, 0xad, 0x6e, 0x78, 0xb0, 0x5f, 0x9a, 0x00,
154         0x11, 0x74, 0x2c, 0x8b, 0xaf, 0x09, 0x65, 0x7c,
155         0x86, 0x8e, 0x55, 0xcb, 0x39, 0x55, 0x72, 0xc6};
156
157 static const unsigned char serv_pub_key_y[] = {
158         0x65, 0x71, 0xcd, 0x03, 0xdc, 0x2a, 0x4f, 0x46,
159         0x5b, 0x14, 0xc8, 0x27, 0x74, 0xab, 0xf4, 0x1f,
160         0xc1, 0x35, 0x0d, 0x42, 0xbc, 0xc2, 0x9f, 0xb5,
161         0xc1, 0x79, 0xb6, 0x8b, 0xca, 0xdb, 0xff, 0x82};
162
163
164 static unsigned char x509_client_cert[DTLS_MAX_CERT_SIZE];
165 static size_t x509_client_cert_len = 0;
166 static unsigned char x509_client_priv[DTLS_PRIVATE_KEY_SIZE+1];
167 static size_t x509_client_priv_is_set = 0;
168 static unsigned char x509_ca_pub[DTLS_PUBLIC_KEY_SIZE+1];
169 static size_t x509_ca_pub_is_set = 0;
170
171 static int x509_info_from_file = 0;
172 #endif /*DTLS_X509*/
173 #ifdef DTLS_ECC
174 static const unsigned char ecdsa_priv_key[] = {
175                         0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
176                         0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
177                         0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
178                         0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA};
179
180 static const unsigned char ecdsa_pub_key_x[] = {
181                         0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
182                         0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
183                         0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
184                         0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52};
185
186 static const unsigned char ecdsa_pub_key_y[] = {
187                         0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
188                         0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
189                         0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
190                         0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29};
191
192 #endif /*DTLS_ECC*/
193 #if defined(DTLS_PSK) || defined(DTLS_X509)
194 ssize_t
195 read_from_file(char *arg, unsigned char *buf, size_t max_buf_len) {
196   FILE *f;
197   ssize_t result = 0;
198
199   f = fopen(arg, "r");
200   if (f == NULL)
201     return -1;
202
203   while (!feof(f)) {
204     size_t bytes_read;
205     bytes_read = fread(buf, 1, max_buf_len, f);
206     if (ferror(f)) {
207       result = -1;
208       break;
209     }
210
211     buf += bytes_read;
212     result += bytes_read;
213     max_buf_len -= bytes_read;
214   }
215   fclose(f);
216   return result;
217 }
218 #endif /*DTLS_PSK||DTLS_X509*/
219 #ifdef DTLS_PSK
220 /* The PSK information for DTLS */
221 #define PSK_ID_MAXLEN 256
222 #define PSK_MAXLEN 256
223 static unsigned char psk_client_id[PSK_ID_MAXLEN];
224 static size_t psk_client_id_length = 0;
225 static unsigned char psk_server_id[PSK_ID_MAXLEN];
226 static size_t psk_server_id_length = 0;
227 static unsigned char psk_key[PSK_MAXLEN];
228 static size_t psk_key_length = 0;
229
230 /* This function is the "key store" for tinyDTLS. It is called to
231  * retrieve a key for the given identity within this particular
232  * session. */
233 static int
234 get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
235             const session_t *session UNUSED_PARAM,
236             dtls_credentials_type_t type,
237             const unsigned char *id, size_t id_len,
238             unsigned char *result, size_t result_length) {
239
240   switch (type) {
241   case DTLS_PSK_IDENTITY:
242     if (id_len) {
243       dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
244     }
245
246     if (result_length < psk_client_id_length) {
247       dtls_warn("cannot set psk_identity -- buffer too small\n");
248       return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
249     }
250
251     memcpy(result, psk_client_id, psk_client_id_length);
252     return psk_client_id_length;
253   case DTLS_PSK_KEY:
254     if (id_len != psk_server_id_length || memcmp(psk_server_id, id, id_len) != 0) {
255       dtls_debug("PSK for unknown id requested\n");
256     }
257     if (result_length < psk_key_length) {
258       dtls_warn("cannot set psk -- buffer too small\n");
259       return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
260     }
261
262     memcpy(result, psk_key, psk_key_length);
263     return psk_key_length;
264   default:
265     dtls_warn("unsupported request type: %d\n", type);
266   }
267
268   return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
269 }
270 #endif /* DTLS_PSK */
271
272 #ifdef DTLS_ECC
273 static int
274 get_ecdsa_key(struct dtls_context_t *ctx,
275               const session_t *session,
276               const dtls_ecc_key_t **result) {
277     (void)ctx;
278     (void)session;
279   static const dtls_ecc_key_t ecdsa_key = {
280     .curve = DTLS_ECDH_CURVE_SECP256R1,
281     .priv_key = ecdsa_priv_key,
282     .pub_key_x = ecdsa_pub_key_x,
283     .pub_key_y = ecdsa_pub_key_y
284   };
285   *result = &ecdsa_key;
286   return 0;
287 }
288
289 static int
290 verify_ecdsa_key(struct dtls_context_t *ctx,
291                  const session_t *session,
292                  const unsigned char *other_pub_x,
293                  const unsigned char *other_pub_y,
294                  size_t key_size) {
295   (void)ctx;
296   (void)session;
297   (void)other_pub_x;
298   (void)other_pub_y;
299   (void)key_size;
300   return 0;
301 }
302
303 #endif /* DTLS_ECC */
304
305 #ifdef DTLS_X509
306 static int
307 get_x509_key(struct dtls_context_t *ctx,
308           const session_t *session,
309           const dtls_ecc_key_t **result) {
310     (void)ctx;
311     (void)session;
312   static dtls_ecc_key_t ecdsa_key = {
313     .curve = DTLS_ECDH_CURVE_SECP256R1,
314     .priv_key = x509_priv_key,
315     .pub_key_x = x509_pub_key_x,
316     .pub_key_y = x509_pub_key_y
317   };
318   if (x509_info_from_file)
319       ecdsa_key.priv_key = x509_client_priv;
320   *result = &ecdsa_key;
321   return 0;
322 }
323
324 static int
325 get_x509_cert(struct dtls_context_t *ctx,
326         const session_t *session,
327         const unsigned char **cert,
328         size_t *cert_size)
329 {
330     (void)ctx;
331     (void)session;
332     if (x509_info_from_file)
333     {
334         *cert = x509_client_cert;
335         *cert_size = x509_client_cert_len;
336     }
337     else
338     {
339         *cert = g_client_certificate;
340         *cert_size = CLIENT_CRT_LEN;
341     }
342
343     return 0;
344 }
345
346 int check_certificate(byte_array cert_der_code, byte_array ca_public_key)
347 {
348     (void)cert_der_code;
349     (void)ca_public_key;
350     return 0;
351 }
352
353 static int verify_x509_cert(struct dtls_context_t *ctx, const session_t *session,
354                                   const unsigned char *cert, size_t cert_size,
355                                   unsigned char *x,
356                                   size_t x_size,
357                                   unsigned char *y,
358                                   size_t y_size)
359 {
360     int ret;
361     const unsigned char *ca_pub_x;
362     const unsigned char *ca_pub_y;
363     byte_array cert_der_code = BYTE_ARRAY_INITIALIZER;
364     byte_array ca_public_key = BYTE_ARRAY_INITIALIZER;
365     unsigned char ca_pub_key[DTLS_PUBLIC_KEY_SIZE];
366     (void)ctx;
367     (void)session;
368
369     if (x509_info_from_file)
370     {
371         ca_pub_x = x509_ca_pub;
372         ca_pub_y = x509_ca_pub + DTLS_PUBLIC_KEY_SIZE/2;
373     }
374     else
375     {
376         ca_pub_x = x509_ca_pub_x;
377         ca_pub_y = x509_ca_pub_y;
378     }
379
380     cert_der_code.data = (uint8_t *)cert;
381     cert_der_code.len = cert_size;
382
383     ca_public_key.len = DTLS_PUBLIC_KEY_SIZE;
384     ca_public_key.data = ca_pub_key;
385     memcpy(ca_public_key.data, ca_pub_x, DTLS_PUBLIC_KEY_SIZE/2);
386     memcpy(ca_public_key.data + DTLS_PUBLIC_KEY_SIZE/2, ca_pub_y, DTLS_PUBLIC_KEY_SIZE/2);
387
388     memcpy(x, serv_pub_key_x, x_size);
389     memcpy(y, serv_pub_key_y, y_size);
390
391     ret = (int) check_certificate(cert_der_code, ca_public_key);
392
393     return -ret;
394 }
395
396 static int is_x509_active(struct dtls_context_t *ctx)
397 {
398     (void)ctx;
399     return 0;
400 }
401
402 #endif /* DTLS_X509 */
403
404 static void
405 try_send(struct dtls_context_t *ctx, session_t *dst) {
406   int res;
407   res = dtls_write(ctx, dst, (uint8 *)buf, len);
408   if (res >= 0) {
409     memmove(buf, buf + res, len - res);
410     len -= res;
411   }
412 }
413
414 static void
415 handle_stdin() {
416   if (fgets(buf + len, sizeof(buf) - len, stdin))
417     len += strlen(buf + len);
418 }
419
420 static int
421 read_from_peer(struct dtls_context_t *ctx, 
422                session_t *session, uint8 *data, size_t len) {
423   size_t i;
424   (void)ctx;
425   (void)session;
426   for (i = 0; i < len; i++)
427     printf("%c", data[i]);
428   return 0;
429 }
430
431 static int
432 send_to_peer(struct dtls_context_t *ctx, 
433              session_t *session, uint8 *data, size_t len) {
434
435   int fd = *(int *)dtls_get_app_data(ctx);
436   return sendto(fd, data, len, MSG_DONTWAIT,
437                 &session->addr.sa, session->size);
438 }
439
440 static int
441 dtls_handle_read(struct dtls_context_t *ctx) {
442   int fd;
443   session_t session;
444 #define MAX_READ_BUF 2000
445   static uint8 buf[MAX_READ_BUF];
446   int len;
447
448   fd = *(int *)dtls_get_app_data(ctx);
449   
450   if (!fd)
451     return -1;
452
453   memset(&session, 0, sizeof(session_t));
454   session.size = sizeof(session.addr);
455   len = recvfrom(fd, buf, MAX_READ_BUF, 0, 
456                  &session.addr.sa, &session.size);
457   
458   if (len < 0) {
459     perror("recvfrom");
460     return -1;
461   } else {
462     dtls_dsrv_log_addr(DTLS_LOG_DEBUG, "peer", &session);
463     dtls_debug_dump("bytes from peer", buf, len);
464   }
465
466   return dtls_handle_message(ctx, &session, buf, len);
467 }    
468
469 static void dtls_handle_signal(int sig)
470 {
471   dtls_free_context(dtls_context);
472   dtls_free_context(orig_dtls_context);
473   signal(sig, SIG_DFL);
474   kill(getpid(), sig);
475 }
476
477 /* stolen from libcoap: */
478 static int
479 resolve_address(const char *server, struct sockaddr *dst) {
480   
481   struct addrinfo *res, *ainfo;
482   struct addrinfo hints;
483   static char addrstr[256];
484   int error;
485
486   memset(addrstr, 0, sizeof(addrstr));
487   if (server && strlen(server) > 0)
488     memcpy(addrstr, server, strlen(server));
489   else
490     memcpy(addrstr, "localhost", 9);
491
492   memset ((char *)&hints, 0, sizeof(hints));
493   hints.ai_socktype = SOCK_DGRAM;
494   hints.ai_family = AF_UNSPEC;
495
496   error = getaddrinfo(addrstr, "", &hints, &res);
497
498   if (error != 0) {
499     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
500     return error;
501   }
502
503   for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
504
505     switch (ainfo->ai_family) {
506     case AF_INET6:
507     case AF_INET:
508
509       memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
510       return ainfo->ai_addrlen;
511     default:
512       ;
513     }
514   }
515
516   freeaddrinfo(res);
517   return -1;
518 }
519
520 /*---------------------------------------------------------------------------*/
521 static void
522 usage( const char *program, const char *version) {
523   const char *p;
524
525   p = strrchr( program, '/' );
526   if ( p )
527     program = ++p;
528
529   fprintf(stderr, "%s v%s -- DTLS client implementation\n"
530           "(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
531           "usage: %s"
532 #ifdef DTLS_PSK
533           " [-i file] [-s file] [-k file]"
534 #endif /* DTLS_PSK */
535 #ifdef DTLS_X509
536           " [-x file] [-r file] [-u file]"
537 #endif /* DTLS_X509 */
538           " [-o file] [-p port] [-v num] [-c num] addr [port]\n"
539 #ifdef DTLS_PSK
540           "\t-i file\t\tread PSK Client identity from file\n"
541           "\t-s file\t\tread PSK Server identity from file\n"
542           "\t-k file\t\tread pre-shared key from file\n"
543 #endif /* DTLS_PSK */
544 #ifdef DTLS_X509
545           "\t-x file\tread Client certificate from file\n"
546           "\t-r file\tread Client private key from file\n"
547           "\t-u file\tread CA public key from file\n"
548 #endif /* DTLS_X509 */
549           "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n"
550           "\t-p port\t\tlisten on specified port (default is %d)\n"
551           "\t-v num\t\tverbosity level (default: 3)\n"
552           "\t-c num\t\tcipher suite (default: 1)\n"
553           "\t\t\t1: TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 \n"
554           "\t\t\t2: TLS_PSK_WITH_AES_128_CCM_8\n"
555           "\t\t\t3: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n"
556           "\t\t\t4: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256\n",
557            program, version, program, DEFAULT_PORT);
558 }
559
560 static dtls_handler_t cb = {
561   .write = send_to_peer,
562   .read  = read_from_peer,
563   .event = NULL,
564 #ifdef DTLS_PSK
565   .get_psk_info = get_psk_info,
566 #endif /* DTLS_PSK */
567 #ifdef DTLS_ECC
568   .get_ecdsa_key = get_ecdsa_key,
569   .verify_ecdsa_key = verify_ecdsa_key,
570 #endif /* DTLS_ECC */
571 #ifdef DTLS_X509
572   .get_x509_key = get_x509_key,
573   .verify_x509_cert = verify_x509_cert,
574   .get_x509_cert = get_x509_cert,
575   .is_x509_active = is_x509_active,
576 #endif /* DTLS_X509 */
577
578 };
579
580 #define DTLS_CLIENT_CMD_CLOSE "client:close"
581 #define DTLS_CLIENT_CMD_RENEGOTIATE "client:renegotiate"
582
583 /* As per RFC 6347 section 4.2.8, DTLS Server should support requests
584  * from clients who have silently abandoned the existing association
585  * and initiated a new handshake request by sending a ClientHello.
586  * Below command tests this feature.
587  */
588 #define DTLS_CLIENT_CMD_REHANDSHAKE "client:rehandshake"
589
590 int 
591 main(int argc, char **argv) {
592   fd_set rfds, wfds;
593   struct timeval timeout;
594   unsigned short port = DEFAULT_PORT;
595   char port_str[NI_MAXSERV] = "0";
596   log_t log_level = DTLS_LOG_WARN;
597   int fd, result;
598   int on = 1;
599   dtls_cipher_t selected_cipher = TLS_NULL_WITH_NULL_NULL;
600   dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
601   int opt, res;
602   session_t dst;
603
604   dtls_init();
605   snprintf(port_str, sizeof(port_str), "%d", port);
606
607 #ifdef DTLS_PSK
608   psk_client_id_length = strlen(PSK_CLIENT_IDENTITY);
609   psk_server_id_length = strlen(PSK_SERVER_IDENTITY);
610   psk_key_length = strlen(PSK_DEFAULT_KEY);
611   memcpy(psk_client_id, PSK_CLIENT_IDENTITY, psk_client_id_length);
612   memcpy(psk_server_id, PSK_SERVER_IDENTITY, psk_server_id_length);
613   memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length);
614 #endif /* DTLS_PSK */
615
616   while ((opt = getopt(argc, argv, "p:o:v:c:" PSK_OPTIONS X509_OPTIONS)) != -1) {
617     switch (opt) {
618 #ifdef DTLS_PSK
619     case 'i' : {
620       ssize_t result = read_from_file(optarg, psk_client_id, PSK_ID_MAXLEN);
621       if (result < 0) {
622         dtls_warn("cannot read Client PSK identity\n");
623       } else {
624         psk_client_id_length = result;
625       }
626       break;
627     }
628     case 's' : {
629       ssize_t result = read_from_file(optarg, psk_server_id, PSK_ID_MAXLEN);
630       if (result < 0) {
631         dtls_warn("cannot read Server PSK identity\n");
632       } else {
633         psk_server_id_length = result;
634       }
635       break;
636     }
637     case 'k' : {
638       ssize_t result = read_from_file(optarg, psk_key, PSK_MAXLEN);
639       if (result < 0) {
640         dtls_warn("cannot read PSK\n");
641       } else {
642         psk_key_length = result;
643       }
644       break;
645     }
646 #endif /* DTLS_PSK */
647 #ifdef DTLS_X509
648     case 'x' :
649     {
650       ssize_t result = read_from_file(optarg, x509_client_cert, DTLS_MAX_CERT_SIZE);
651       if (result < 0)
652       {
653           dtls_warn("Cannot read Client certificate. Using default\n");
654       }
655       else
656       {
657           x509_client_cert_len = result;
658       }
659       break;
660     }
661     case 'r' :
662     {
663       ssize_t result = read_from_file(optarg, x509_client_priv, DTLS_PRIVATE_KEY_SIZE+1);
664       if (result < 0)
665       {
666           dtls_warn("Cannot read Client private key. Using default\n");
667       }
668       else
669       {
670           x509_client_priv_is_set = result;
671       }
672       break;
673     }
674     case 'u' :
675     {
676       ssize_t result = read_from_file(optarg, x509_ca_pub, DTLS_PUBLIC_KEY_SIZE+1);
677       if (result < 0)
678       {
679           dtls_warn("Cannot read CA public key. Using default\n");
680       }
681       else
682       {
683           x509_ca_pub_is_set = result;
684       }
685       break;
686     }
687 #endif /* DTLS_X509 */
688     case 'p' :
689       strncpy(port_str, optarg, NI_MAXSERV-1);
690       port_str[NI_MAXSERV - 1] = '\0';
691       break;
692     case 'o' :
693       output_file.length = strlen(optarg);
694       output_file.s = (unsigned char *)malloc(output_file.length + 1);
695
696       if (!output_file.s) {
697         dtls_crit("cannot set output file: insufficient memory\n");
698         exit(-1);
699       } else {
700         /* copy filename including trailing zero */
701         memcpy(output_file.s, optarg, output_file.length + 1);
702       }
703       break;
704     case 'v' :
705       log_level = strtol(optarg, NULL, 10);
706       break;
707     case 'c':
708       if( strcmp(optarg, "1") == 0)
709       {
710           selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256;
711           ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
712       }
713       else if( strcmp(optarg, "2") == 0)
714       {
715           selected_cipher = TLS_PSK_WITH_AES_128_CCM_8 ;
716           ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
717       }
718       else if( strcmp(optarg, "3") == 0)
719       {
720           selected_cipher = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ;
721           ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
722       }
723       else if( strcmp(optarg, "4") == 0)
724       {
725           selected_cipher = TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256;
726           ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
727       }
728       break;
729     default:
730       usage(argv[0], dtls_package_version());
731       exit(1);
732     }
733   }
734
735   dtls_set_log_level(log_level);
736
737   if (argc <= optind) {
738     usage(argv[0], dtls_package_version());
739     exit(1);
740   }
741
742 #ifdef DTLS_X509
743   if (x509_client_cert_len && x509_client_priv_is_set && x509_ca_pub_is_set)
744   {
745       x509_info_from_file = 1;
746   }
747   else if(!(x509_client_cert_len || x509_client_priv_is_set || x509_ca_pub_is_set))
748   {
749       x509_info_from_file = 0;
750   }
751   else
752   {
753       fprintf(stderr,"please set -x, -r, -u options simultaneously");
754       usage(argv[0], dtls_package_version());
755       exit(1);
756   }
757 #endif /* DTLS_X509 */
758
759   memset(&dst, 0, sizeof(session_t));
760   /* resolve destination address where server should be sent */
761   res = resolve_address(argv[optind++], &dst.addr.sa);
762   if (res < 0) {
763     dtls_emerg("failed to resolve address\n");
764     exit(-1);
765   }
766   dst.size = res;
767
768   /* use port number from command line when specified or the listen
769      port, otherwise */
770   dst.addr.sin.sin_port = htons(atoi(optind < argc ? argv[optind++] : port_str));
771
772   
773   /* init socket and set it to non-blocking */
774   fd = socket(dst.addr.sa.sa_family, SOCK_DGRAM, 0);
775
776   if (fd < 0) {
777     dtls_alert("socket: %s\n", strerror(errno));
778     return 0;
779   }
780
781   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
782     dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
783   }
784 #if 0
785   flags = fcntl(fd, F_GETFL, 0);
786   if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
787     dtls_alert("fcntl: %s\n", strerror(errno));
788     goto error;
789   }
790 #endif
791   on = 1;
792 #ifdef IPV6_RECVPKTINFO
793   if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
794 #else /* IPV6_RECVPKTINFO */
795   if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
796 #endif /* IPV6_RECVPKTINFO */
797     dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
798   }
799
800   if (signal(SIGINT, dtls_handle_signal) == SIG_ERR) {
801     dtls_alert("An error occurred while setting a signal handler.\n");
802     return EXIT_FAILURE;
803   }
804
805   dtls_context = dtls_new_context(&fd);
806   if (!dtls_context) {
807     dtls_emerg("cannot create context\n");
808     exit(-1);
809   }
810
811
812   /* select cipher suite */
813   dtls_select_cipher(dtls_context, selected_cipher);
814
815   /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */
816   dtls_enables_anon_ecdh(dtls_context, ecdh_anon_enalbe);
817
818   dtls_set_handler(dtls_context, &cb);
819
820   dtls_connect(dtls_context, &dst);
821
822   while (1) {
823     FD_ZERO(&rfds);
824     FD_ZERO(&wfds);
825
826     FD_SET(fileno(stdin), &rfds);
827     FD_SET(fd, &rfds);
828     /* FD_SET(fd, &wfds); */
829     
830     timeout.tv_sec = 5;
831     timeout.tv_usec = 0;
832     
833     result = select(fd+1, &rfds, &wfds, 0, &timeout);
834     
835     if (result < 0) {           /* error */
836       if (errno != EINTR)
837         perror("select");
838     } else if (result == 0) {   /* timeout */
839     } else {                    /* ok */
840       if (FD_ISSET(fd, &wfds))
841         /* FIXME */;
842       else if (FD_ISSET(fd, &rfds))
843         dtls_handle_read(dtls_context);
844       else if (FD_ISSET(fileno(stdin), &rfds))
845         handle_stdin();
846     }
847
848     if (len) {
849       if (len >= strlen(DTLS_CLIENT_CMD_CLOSE) &&
850           !memcmp(buf, DTLS_CLIENT_CMD_CLOSE, strlen(DTLS_CLIENT_CMD_CLOSE))) {
851         printf("client: closing connection\n");
852         dtls_close(dtls_context, &dst);
853         len = 0;
854       } else if (len >= strlen(DTLS_CLIENT_CMD_RENEGOTIATE) &&
855                  !memcmp(buf, DTLS_CLIENT_CMD_RENEGOTIATE, strlen(DTLS_CLIENT_CMD_RENEGOTIATE))) {
856         printf("client: renegotiate connection\n");
857         dtls_renegotiate(dtls_context, &dst);
858         len = 0;
859       } else if (len >= strlen(DTLS_CLIENT_CMD_REHANDSHAKE) &&
860                  !memcmp(buf, DTLS_CLIENT_CMD_REHANDSHAKE, strlen(DTLS_CLIENT_CMD_REHANDSHAKE))) {
861         printf("client: rehandshake connection\n");
862         if (orig_dtls_context == NULL) {
863           /* Cache the current context. We cannot free the current context as it will notify 
864            * the Server to close the connection (which we do not want).
865            */
866           orig_dtls_context = dtls_context;
867           /* Now, Create a new context and attempt to initiate a handshake. */
868           dtls_context = dtls_new_context(&fd);
869           if (!dtls_context) {
870             dtls_emerg("cannot create context\n");
871             exit(-1);
872           }
873           dtls_set_handler(dtls_context, &cb);
874           dtls_connect(dtls_context, &dst);
875         }
876         len = 0;
877       } else {
878         try_send(dtls_context, &dst);
879       }
880     }
881   }
882   
883   dtls_free_context(dtls_context);
884   dtls_free_context(orig_dtls_context);
885   exit(0);
886 }
887