ae1283e2f3e08eacf45455d2d83ca4ea213ea758
[platform/upstream/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
51 #define PSK_SERVER_HINT  "Server_identity"
52
53 /* This function is the "key store" for tinyDTLS. It is called to
54  * retrieve a key for the given identity within this particular
55  * session. */
56 static int
57 get_psk_info(struct dtls_context_t *ctx, const session_t *session,
58              dtls_credentials_type_t type,
59              const unsigned char *id, size_t id_len,
60              unsigned char *result, size_t result_length) {
61
62   struct keymap_t {
63     unsigned char *id;
64     size_t id_length;
65     unsigned char *key;
66     size_t key_length;
67   } psk[3] = {
68     { (unsigned char *)"Client_identity", 15,
69       (unsigned char *)"secretPSK", 9 },
70     { (unsigned char *)"default identity", 16,
71       (unsigned char *)"\x11\x22\x33", 3 },
72     { (unsigned char *)"\0", 2,
73       (unsigned char *)"", 1 }
74   };
75
76   switch (type) {
77   case DTLS_PSK_HINT:
78     if (result_length < strlen(PSK_SERVER_HINT)) {
79       dtls_warn("cannot set psk_hint -- buffer too small\n");
80       return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
81     }
82
83     memcpy(result, PSK_SERVER_HINT, strlen(PSK_SERVER_HINT));
84     return strlen(PSK_SERVER_HINT);
85
86   case DTLS_PSK_KEY:
87     if (id) {
88       int i;
89       for (i = 0; i < sizeof(psk)/sizeof(struct keymap_t); i++) {
90         if (id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
91           if (result_length < psk[i].key_length) {
92             dtls_warn("buffer too small for PSK");
93             return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
94           }
95
96           memcpy(result, psk[i].key, psk[i].key_length);
97           return psk[i].key_length;
98         }
99       }
100     }
101     break;
102
103   default:
104     dtls_warn("unsupported request type: %d\n", type);
105   }
106
107   return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
108 }
109
110 #endif /* DTLS_PSK */
111
112 #ifdef DTLS_ECC
113 static int
114 get_ecdsa_key(struct dtls_context_t *ctx,
115               const session_t *session,
116               const dtls_ecdsa_key_t **result) {
117   static const dtls_ecdsa_key_t ecdsa_key = {
118     .curve = DTLS_ECDH_CURVE_SECP256R1,
119     .priv_key = ecdsa_priv_key,
120     .pub_key_x = ecdsa_pub_key_x,
121     .pub_key_y = ecdsa_pub_key_y
122   };
123
124   *result = &ecdsa_key;
125   return 0;
126 }
127
128 static int
129 verify_ecdsa_key(struct dtls_context_t *ctx,
130                  const session_t *session,
131                  const unsigned char *other_pub_x,
132                  const unsigned char *other_pub_y,
133                  size_t key_size) {
134   return 0;
135 }
136 #endif /* DTLS_ECC */
137
138 #define DTLS_SERVER_CMD_CLOSE "server:close"
139 #define DTLS_SERVER_CMD_RENEGOTIATE "server:renegotiate"
140
141 static int
142 read_from_peer(struct dtls_context_t *ctx, 
143                session_t *session, uint8 *data, size_t len) {
144   size_t i;
145   for (i = 0; i < len; i++)
146     printf("%c", data[i]);
147   if (len >= strlen(DTLS_SERVER_CMD_CLOSE) &&
148       !memcmp(data, DTLS_SERVER_CMD_CLOSE, strlen(DTLS_SERVER_CMD_CLOSE))) {
149     printf("server: closing connection\n");
150     dtls_close(ctx, session);
151     return len;
152   } else if (len >= strlen(DTLS_SERVER_CMD_RENEGOTIATE) &&
153       !memcmp(data, DTLS_SERVER_CMD_RENEGOTIATE, strlen(DTLS_SERVER_CMD_RENEGOTIATE))) {
154     printf("server: renegotiate connection\n");
155     dtls_renegotiate(ctx, session);
156     return len;
157   }
158
159   return dtls_write(ctx, session, data, len);
160 }
161
162 static int
163 send_to_peer(struct dtls_context_t *ctx, 
164              session_t *session, uint8 *data, size_t len) {
165
166   int fd = *(int *)dtls_get_app_data(ctx);
167   return sendto(fd, data, len, MSG_DONTWAIT,
168                 &session->addr.sa, session->size);
169 }
170
171 static int
172 dtls_handle_read(struct dtls_context_t *ctx) {
173   int *fd;
174   session_t session;
175   static uint8 buf[DTLS_MAX_BUF];
176   int len;
177
178   fd = dtls_get_app_data(ctx);
179
180   assert(fd);
181
182   memset(&session, 0, sizeof(session_t));
183   session.size = sizeof(session.addr);
184   len = recvfrom(*fd, buf, sizeof(buf), MSG_TRUNC,
185                  &session.addr.sa, &session.size);
186
187   if (len < 0) {
188     perror("recvfrom");
189     return -1;
190   } else {
191     dtls_debug("got %d bytes from port %d\n", len, 
192              ntohs(session.addr.sin6.sin6_port));
193     if (sizeof(buf) < len) {
194       dtls_warn("packet was truncated (%d bytes lost)\n", len - sizeof(buf));
195     }
196   }
197
198   return dtls_handle_message(ctx, &session, buf, len);
199 }    
200
201 static int
202 resolve_address(const char *server, struct sockaddr *dst) {
203   
204   struct addrinfo *res, *ainfo;
205   struct addrinfo hints;
206   static char addrstr[256];
207   int error;
208
209   memset(addrstr, 0, sizeof(addrstr));
210   if (server && strlen(server) > 0)
211     memcpy(addrstr, server, strlen(server));
212   else
213     memcpy(addrstr, "localhost", 9);
214
215   memset ((char *)&hints, 0, sizeof(hints));
216   hints.ai_socktype = SOCK_DGRAM;
217   hints.ai_family = AF_UNSPEC;
218
219   error = getaddrinfo(addrstr, "", &hints, &res);
220
221   if (error != 0) {
222     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
223     return error;
224   }
225
226   for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
227
228     switch (ainfo->ai_family) {
229     case AF_INET6:
230
231       memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
232       return ainfo->ai_addrlen;
233     default:
234       ;
235     }
236   }
237
238   freeaddrinfo(res);
239   return -1;
240 }
241
242 static void
243 usage(const char *program, const char *version) {
244   const char *p;
245
246   p = strrchr( program, '/' );
247   if ( p )
248     program = ++p;
249
250   fprintf(stderr, "%s v%s -- DTLS server implementation\n"
251           "(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
252           "usage: %s [-A address] [-p port] [-v num]\n"
253           "\t-A address\t\tlisten on specified address (default is ::)\n"
254           "\t-p port\t\tlisten on specified port (default is %d)\n"
255           "\t-v num\t\tverbosity level (default: 3)\n",
256            program, version, program, DEFAULT_PORT);
257 }
258
259 static dtls_handler_t cb = {
260   .write = send_to_peer,
261   .read  = read_from_peer,
262   .event = NULL,
263 #ifdef DTLS_PSK
264   .get_psk_info = get_psk_info,
265 #endif /* DTLS_PSK */
266 #ifdef DTLS_ECC
267   .get_ecdsa_key = get_ecdsa_key,
268   .verify_ecdsa_key = verify_ecdsa_key
269 #endif /* DTLS_ECC */
270 };
271
272 int 
273 main(int argc, char **argv) {
274   dtls_context_t *the_context = NULL;
275   log_t log_level = DTLS_LOG_WARN;
276   fd_set rfds, wfds;
277   struct timeval timeout;
278   int fd, opt, result;
279   int on = 1;
280   struct sockaddr_in6 listen_addr;
281
282   memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
283
284   /* fill extra field for 4.4BSD-based systems (see RFC 3493, section 3.4) */
285 #if defined(SIN6_LEN) || defined(HAVE_SOCKADDR_IN6_SIN6_LEN)
286   listen_addr.sin6_len = sizeof(struct sockaddr_in6);
287 #endif
288
289   listen_addr.sin6_family = AF_INET6;
290   listen_addr.sin6_port = htons(DEFAULT_PORT);
291   listen_addr.sin6_addr = in6addr_any;
292
293   while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
294     switch (opt) {
295     case 'A' :
296       if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) {
297         fprintf(stderr, "cannot resolve address\n");
298         exit(-1);
299       }
300       break;
301     case 'p' :
302       listen_addr.sin6_port = htons(atoi(optarg));
303       break;
304     case 'v' :
305       log_level = strtol(optarg, NULL, 10);
306       break;
307     default:
308       usage(argv[0], dtls_package_version());
309       exit(1);
310     }
311   }
312
313   dtls_set_log_level(log_level);
314
315   /* init socket and set it to non-blocking */
316   fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
317
318   if (fd < 0) {
319     dtls_alert("socket: %s\n", strerror(errno));
320     return 0;
321   }
322
323   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
324     dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
325   }
326 #if 0
327   flags = fcntl(fd, F_GETFL, 0);
328   if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
329     dtls_alert("fcntl: %s\n", strerror(errno));
330     goto error;
331   }
332 #endif
333   on = 1;
334 #ifdef IPV6_RECVPKTINFO
335   if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
336 #else /* IPV6_RECVPKTINFO */
337   if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
338 #endif /* IPV6_RECVPKTINFO */
339     dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
340   }
341
342   if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
343     dtls_alert("bind: %s\n", strerror(errno));
344     goto error;
345   }
346
347   dtls_init();
348
349   the_context = dtls_new_context(&fd);
350
351   dtls_set_handler(the_context, &cb);
352
353   while (1) {
354     FD_ZERO(&rfds);
355     FD_ZERO(&wfds);
356
357     FD_SET(fd, &rfds);
358     /* FD_SET(fd, &wfds); */
359     
360     timeout.tv_sec = 5;
361     timeout.tv_usec = 0;
362     
363     result = select( fd+1, &rfds, &wfds, 0, &timeout);
364     
365     if (result < 0) {           /* error */
366       if (errno != EINTR)
367         perror("select");
368     } else if (result == 0) {   /* timeout */
369     } else {                    /* ok */
370       if (FD_ISSET(fd, &wfds))
371         ;
372       else if (FD_ISSET(fd, &rfds)) {
373         dtls_handle_read(the_context);
374       }
375     }
376   }
377   
378  error:
379   dtls_free_context(the_context);
380   exit(0);
381 }