Adding tinyDTLS into iotivity repo
[contrib/iotivity.git] / extlibs / tinydtls / tests / dtls-server.c
1
2 /* This is needed for apple */
3 #define __APPLE_USE_RFC_3542
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <netinet/in.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/time.h>
14 #include <netdb.h>
15 #include <signal.h>
16
17 #include "tinydtls.h" 
18 #include "dtls.h" 
19 #include "debug.h" 
20
21 #define DEFAULT_PORT 20220
22
23 static const unsigned char ecdsa_priv_key[] = {
24                         0xD9, 0xE2, 0x70, 0x7A, 0x72, 0xDA, 0x6A, 0x05,
25                         0x04, 0x99, 0x5C, 0x86, 0xED, 0xDB, 0xE3, 0xEF,
26                         0xC7, 0xF1, 0xCD, 0x74, 0x83, 0x8F, 0x75, 0x70,
27                         0xC8, 0x07, 0x2D, 0x0A, 0x76, 0x26, 0x1B, 0xD4};
28
29 static const unsigned char ecdsa_pub_key_x[] = {
30                         0xD0, 0x55, 0xEE, 0x14, 0x08, 0x4D, 0x6E, 0x06,
31                         0x15, 0x59, 0x9D, 0xB5, 0x83, 0x91, 0x3E, 0x4A,
32                         0x3E, 0x45, 0x26, 0xA2, 0x70, 0x4D, 0x61, 0xF2,
33                         0x7A, 0x4C, 0xCF, 0xBA, 0x97, 0x58, 0xEF, 0x9A};
34
35 static const unsigned char ecdsa_pub_key_y[] = {
36                         0xB4, 0x18, 0xB6, 0x4A, 0xFE, 0x80, 0x30, 0xDA,
37                         0x1D, 0xDC, 0xF4, 0xF4, 0x2E, 0x2F, 0x26, 0x31,
38                         0xD0, 0x43, 0xB1, 0xFB, 0x03, 0xE2, 0x2F, 0x4D,
39                         0x17, 0xDE, 0x43, 0xF9, 0xF9, 0xAD, 0xEE, 0x70};
40
41 #if 0
42 /* SIGINT handler: set quit to 1 for graceful termination */
43 void
44 handle_sigint(int signum) {
45   dsrv_stop(dsrv_get_context());
46 }
47 #endif
48
49 #ifdef DTLS_PSK
50 /* This function is the "key store" for tinyDTLS. It is called to
51  * retrieve a key for the given identity within this particular
52  * session. */
53 static int
54 get_psk_info(struct dtls_context_t *ctx, const session_t *session,
55              dtls_credentials_type_t type,
56              const unsigned char *id, size_t id_len,
57              unsigned char *result, size_t result_length) {
58
59   struct keymap_t {
60     unsigned char *id;
61     size_t id_length;
62     unsigned char *key;
63     size_t key_length;
64   } psk[3] = {
65     { (unsigned char *)"Client_identity", 15,
66       (unsigned char *)"secretPSK", 9 },
67     { (unsigned char *)"default identity", 16,
68       (unsigned char *)"\x11\x22\x33", 3 },
69     { (unsigned char *)"\0", 2,
70       (unsigned char *)"", 1 }
71   };
72
73   if (type != DTLS_PSK_KEY) {
74     return 0;
75   }
76
77   if (id) {
78     int i;
79     for (i = 0; i < sizeof(psk)/sizeof(struct keymap_t); i++) {
80       if (id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
81         if (result_length < psk[i].key_length) {
82           dtls_warn("buffer too small for PSK");
83           return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
84         }
85
86         memcpy(result, psk[i].key, psk[i].key_length);
87         return psk[i].key_length;
88       }
89     }
90   }
91
92   return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
93 }
94
95 #endif /* DTLS_PSK */
96
97 #ifdef DTLS_ECC
98 static int
99 get_ecdsa_key(struct dtls_context_t *ctx,
100               const session_t *session,
101               const dtls_ecdsa_key_t **result) {
102   static const dtls_ecdsa_key_t ecdsa_key = {
103     .curve = DTLS_ECDH_CURVE_SECP256R1,
104     .priv_key = ecdsa_priv_key,
105     .pub_key_x = ecdsa_pub_key_x,
106     .pub_key_y = ecdsa_pub_key_y
107   };
108
109   *result = &ecdsa_key;
110   return 0;
111 }
112
113 static int
114 verify_ecdsa_key(struct dtls_context_t *ctx,
115                  const session_t *session,
116                  const unsigned char *other_pub_x,
117                  const unsigned char *other_pub_y,
118                  size_t key_size) {
119   return 0;
120 }
121 #endif /* DTLS_ECC */
122
123 #define DTLS_SERVER_CMD_CLOSE "server:close"
124 #define DTLS_SERVER_CMD_RENEGOTIATE "server:renegotiate"
125
126 static int
127 read_from_peer(struct dtls_context_t *ctx, 
128                session_t *session, uint8 *data, size_t len) {
129   size_t i;
130   for (i = 0; i < len; i++)
131     printf("%c", data[i]);
132   if (len >= strlen(DTLS_SERVER_CMD_CLOSE) &&
133       !memcmp(data, DTLS_SERVER_CMD_CLOSE, strlen(DTLS_SERVER_CMD_CLOSE))) {
134     printf("server: closing connection\n");
135     dtls_close(ctx, session);
136     return len;
137   } else if (len >= strlen(DTLS_SERVER_CMD_RENEGOTIATE) &&
138       !memcmp(data, DTLS_SERVER_CMD_RENEGOTIATE, strlen(DTLS_SERVER_CMD_RENEGOTIATE))) {
139     printf("server: renegotiate connection\n");
140     dtls_renegotiate(ctx, session);
141     return len;
142   }
143
144   return dtls_write(ctx, session, data, len);
145 }
146
147 static int
148 send_to_peer(struct dtls_context_t *ctx, 
149              session_t *session, uint8 *data, size_t len) {
150
151   int fd = *(int *)dtls_get_app_data(ctx);
152   return sendto(fd, data, len, MSG_DONTWAIT,
153                 &session->addr.sa, session->size);
154 }
155
156 static int
157 dtls_handle_read(struct dtls_context_t *ctx) {
158   int *fd;
159   session_t session;
160   static uint8 buf[DTLS_MAX_BUF];
161   int len;
162
163   fd = dtls_get_app_data(ctx);
164
165   assert(fd);
166
167   memset(&session, 0, sizeof(session_t));
168   session.size = sizeof(session.addr);
169   len = recvfrom(*fd, buf, sizeof(buf), MSG_TRUNC,
170                  &session.addr.sa, &session.size);
171
172   if (len < 0) {
173     perror("recvfrom");
174     return -1;
175   } else {
176     dtls_debug("got %d bytes from port %d\n", len, 
177              ntohs(session.addr.sin6.sin6_port));
178     if (sizeof(buf) < len) {
179       dtls_warn("packet was truncated (%d bytes lost)\n", len - sizeof(buf));
180     }
181   }
182
183   return dtls_handle_message(ctx, &session, buf, len);
184 }    
185
186 static int
187 resolve_address(const char *server, struct sockaddr *dst) {
188   
189   struct addrinfo *res, *ainfo;
190   struct addrinfo hints;
191   static char addrstr[256];
192   int error;
193
194   memset(addrstr, 0, sizeof(addrstr));
195   if (server && strlen(server) > 0)
196     memcpy(addrstr, server, strlen(server));
197   else
198     memcpy(addrstr, "localhost", 9);
199
200   memset ((char *)&hints, 0, sizeof(hints));
201   hints.ai_socktype = SOCK_DGRAM;
202   hints.ai_family = AF_UNSPEC;
203
204   error = getaddrinfo(addrstr, "", &hints, &res);
205
206   if (error != 0) {
207     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
208     return error;
209   }
210
211   for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
212
213     switch (ainfo->ai_family) {
214     case AF_INET6:
215
216       memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
217       return ainfo->ai_addrlen;
218     default:
219       ;
220     }
221   }
222
223   freeaddrinfo(res);
224   return -1;
225 }
226
227 static void
228 usage(const char *program, const char *version) {
229   const char *p;
230
231   p = strrchr( program, '/' );
232   if ( p )
233     program = ++p;
234
235   fprintf(stderr, "%s v%s -- DTLS server implementation\n"
236           "(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
237           "usage: %s [-A address] [-p port] [-v num]\n"
238           "\t-A address\t\tlisten on specified address (default is ::)\n"
239           "\t-p port\t\tlisten on specified port (default is %d)\n"
240           "\t-v num\t\tverbosity level (default: 3)\n",
241            program, version, program, DEFAULT_PORT);
242 }
243
244 static dtls_handler_t cb = {
245   .write = send_to_peer,
246   .read  = read_from_peer,
247   .event = NULL,
248 #ifdef DTLS_PSK
249   .get_psk_info = get_psk_info,
250 #endif /* DTLS_PSK */
251 #ifdef DTLS_ECC
252   .get_ecdsa_key = get_ecdsa_key,
253   .verify_ecdsa_key = verify_ecdsa_key
254 #endif /* DTLS_ECC */
255 };
256
257 int 
258 main(int argc, char **argv) {
259   dtls_context_t *the_context = NULL;
260   log_t log_level = DTLS_LOG_WARN;
261   fd_set rfds, wfds;
262   struct timeval timeout;
263   int fd, opt, result;
264   int on = 1;
265   struct sockaddr_in6 listen_addr;
266
267   memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
268
269   /* fill extra field for 4.4BSD-based systems (see RFC 3493, section 3.4) */
270 #if defined(SIN6_LEN) || defined(HAVE_SOCKADDR_IN6_SIN6_LEN)
271   listen_addr.sin6_len = sizeof(struct sockaddr_in6);
272 #endif
273
274   listen_addr.sin6_family = AF_INET6;
275   listen_addr.sin6_port = htons(DEFAULT_PORT);
276   listen_addr.sin6_addr = in6addr_any;
277
278   while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
279     switch (opt) {
280     case 'A' :
281       if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) {
282         fprintf(stderr, "cannot resolve address\n");
283         exit(-1);
284       }
285       break;
286     case 'p' :
287       listen_addr.sin6_port = htons(atoi(optarg));
288       break;
289     case 'v' :
290       log_level = strtol(optarg, NULL, 10);
291       break;
292     default:
293       usage(argv[0], dtls_package_version());
294       exit(1);
295     }
296   }
297
298   dtls_set_log_level(log_level);
299
300   /* init socket and set it to non-blocking */
301   fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
302
303   if (fd < 0) {
304     dtls_alert("socket: %s\n", strerror(errno));
305     return 0;
306   }
307
308   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
309     dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
310   }
311 #if 0
312   flags = fcntl(fd, F_GETFL, 0);
313   if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
314     dtls_alert("fcntl: %s\n", strerror(errno));
315     goto error;
316   }
317 #endif
318   on = 1;
319 #ifdef IPV6_RECVPKTINFO
320   if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
321 #else /* IPV6_RECVPKTINFO */
322   if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
323 #endif /* IPV6_RECVPKTINFO */
324     dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
325   }
326
327   if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
328     dtls_alert("bind: %s\n", strerror(errno));
329     goto error;
330   }
331
332   dtls_init();
333
334   the_context = dtls_new_context(&fd);
335
336   dtls_set_handler(the_context, &cb);
337
338   while (1) {
339     FD_ZERO(&rfds);
340     FD_ZERO(&wfds);
341
342     FD_SET(fd, &rfds);
343     /* FD_SET(fd, &wfds); */
344     
345     timeout.tv_sec = 5;
346     timeout.tv_usec = 0;
347     
348     result = select( fd+1, &rfds, &wfds, 0, &timeout);
349     
350     if (result < 0) {           /* error */
351       if (errno != EINTR)
352         perror("select");
353     } else if (result == 0) {   /* timeout */
354     } else {                    /* ok */
355       if (FD_ISSET(fd, &wfds))
356         ;
357       else if (FD_ISSET(fd, &rfds)) {
358         dtls_handle_read(the_context);
359       }
360     }
361   }
362   
363  error:
364   dtls_free_context(the_context);
365   exit(0);
366 }