Imported Upstream version 0.9.2
[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_ecc_key_t **result) {
117   static const dtls_ecc_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] [-a enable|disable]\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           "\t-a enable|disable\t(default: disable)\n"
257           "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA\n"
258           "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA\n",
259            program, version, program, DEFAULT_PORT);
260 }
261
262 static dtls_handler_t cb = {
263   .write = send_to_peer,
264   .read  = read_from_peer,
265   .event = NULL,
266 #ifdef DTLS_PSK
267   .get_psk_info = get_psk_info,
268 #endif /* DTLS_PSK */
269 #ifdef DTLS_ECC
270   .get_ecdsa_key = get_ecdsa_key,
271   .verify_ecdsa_key = verify_ecdsa_key
272 #endif /* DTLS_ECC */
273 };
274
275 int 
276 main(int argc, char **argv) {
277   dtls_context_t *the_context = NULL;
278   log_t log_level = DTLS_LOG_WARN;
279   fd_set rfds, wfds;
280   struct timeval timeout;
281   int fd, opt, result;
282   int on = 1;
283   int ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
284   struct sockaddr_in6 listen_addr;
285
286   memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
287
288   /* fill extra field for 4.4BSD-based systems (see RFC 3493, section 3.4) */
289 #if defined(SIN6_LEN) || defined(HAVE_SOCKADDR_IN6_SIN6_LEN)
290   listen_addr.sin6_len = sizeof(struct sockaddr_in6);
291 #endif
292
293   listen_addr.sin6_family = AF_INET6;
294   listen_addr.sin6_port = htons(DEFAULT_PORT);
295   listen_addr.sin6_addr = in6addr_any;
296
297   while ((opt = getopt(argc, argv, "A:p:v:a:")) != -1) {
298     switch (opt) {
299     case 'A' :
300       if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) {
301         fprintf(stderr, "cannot resolve address\n");
302         exit(-1);
303       }
304       break;
305     case 'p' :
306       listen_addr.sin6_port = htons(atoi(optarg));
307       break;
308     case 'v' :
309       log_level = strtol(optarg, NULL, 10);
310       break;
311     case 'a':
312       if( strcmp(optarg, "enable") == 0)
313           ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
314       break;
315     default:
316       usage(argv[0], dtls_package_version());
317       exit(1);
318     }
319   }
320
321   dtls_set_log_level(log_level);
322
323   /* init socket and set it to non-blocking */
324   fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
325
326   if (fd < 0) {
327     dtls_alert("socket: %s\n", strerror(errno));
328     return 0;
329   }
330
331   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
332     dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
333   }
334 #if 0
335   flags = fcntl(fd, F_GETFL, 0);
336   if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
337     dtls_alert("fcntl: %s\n", strerror(errno));
338     goto error;
339   }
340 #endif
341   on = 1;
342 #ifdef IPV6_RECVPKTINFO
343   if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
344 #else /* IPV6_RECVPKTINFO */
345   if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
346 #endif /* IPV6_RECVPKTINFO */
347     dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
348   }
349
350   if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
351     dtls_alert("bind: %s\n", strerror(errno));
352     goto error;
353   }
354
355   dtls_init();
356
357   the_context = dtls_new_context(&fd);
358
359   /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */
360   dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe);
361
362   dtls_set_handler(the_context, &cb);
363
364   while (1) {
365     FD_ZERO(&rfds);
366     FD_ZERO(&wfds);
367
368     FD_SET(fd, &rfds);
369     /* FD_SET(fd, &wfds); */
370     
371     timeout.tv_sec = 5;
372     timeout.tv_usec = 0;
373     
374     result = select( fd+1, &rfds, &wfds, 0, &timeout);
375     
376     if (result < 0) {           /* error */
377       if (errno != EINTR)
378         perror("select");
379     } else if (result == 0) {   /* timeout */
380     } else {                    /* ok */
381       if (FD_ISSET(fd, &wfds))
382         ;
383       else if (FD_ISSET(fd, &rfds)) {
384         dtls_handle_read(the_context);
385       }
386     }
387   }
388   
389  error:
390   dtls_free_context(the_context);
391   exit(0);
392 }