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
get_psk_info(struct dtls_context_t * ctx,const session_t * session,dtls_credentials_type_t type,const unsigned char * id,size_t id_len,unsigned char * result,size_t result_length)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
get_ecdsa_key(struct dtls_context_t * ctx,const session_t * session,const dtls_ecdsa_key_t ** result)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
verify_ecdsa_key(struct dtls_context_t * ctx,const session_t * session,const unsigned char * other_pub_x,const unsigned char * other_pub_y,size_t key_size)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
read_from_peer(struct dtls_context_t * ctx,session_t * session,uint8 * data,size_t len)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
send_to_peer(struct dtls_context_t * ctx,session_t * session,uint8 * data,size_t len)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
dtls_handle_read(struct dtls_context_t * ctx)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
resolve_address(const char * server,struct sockaddr * dst)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
usage(const char * program,const char * version)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
handle_event(struct dtls_context_t * ctx,session_t * session,dtls_alert_level_t level,unsigned short code)244 static int handle_event(struct dtls_context_t *ctx, session_t *session,
245 dtls_alert_level_t level, unsigned short code)
246 {
247 printf("event: level %d code %d\n", level, code);
248 if (level > 0) {
249 /* alert code, quit */
250 } else if (level == 0) {
251 /* internal event */
252 if (code == DTLS_EVENT_CONNECTED) {
253 /* We can send data now */
254 }
255 }
256
257 return 0;
258 }
259
260 static dtls_handler_t cb = {
261 .write = send_to_peer,
262 .read = read_from_peer,
263 .event = handle_event,
264 #ifdef DTLS_PSK
265 .get_psk_info = get_psk_info,
266 #endif /* DTLS_PSK */
267 #ifdef DTLS_ECC
268 .get_ecdsa_key = get_ecdsa_key,
269 .verify_ecdsa_key = verify_ecdsa_key
270 #endif /* DTLS_ECC */
271 };
272
273 int
main(int argc,char ** argv)274 main(int argc, char **argv) {
275 dtls_context_t *the_context = NULL;
276 log_t log_level = DTLS_LOG_WARN;
277 fd_set rfds, wfds;
278 struct timeval timeout;
279 int fd, opt, result;
280 int on = 1;
281 struct sockaddr_in6 listen_addr;
282
283 memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
284
285 /* fill extra field for 4.4BSD-based systems (see RFC 3493, section 3.4) */
286 #if defined(SIN6_LEN) || defined(HAVE_SOCKADDR_IN6_SIN6_LEN)
287 listen_addr.sin6_len = sizeof(struct sockaddr_in6);
288 #endif
289
290 listen_addr.sin6_family = AF_INET6;
291 listen_addr.sin6_port = htons(DEFAULT_PORT);
292 listen_addr.sin6_addr = in6addr_any;
293
294 while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
295 switch (opt) {
296 case 'A' :
297 if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) {
298 fprintf(stderr, "cannot resolve address\n");
299 exit(-1);
300 }
301 break;
302 case 'p' :
303 listen_addr.sin6_port = htons(atoi(optarg));
304 break;
305 case 'v' :
306 log_level = strtol(optarg, NULL, 10);
307 break;
308 default:
309 usage(argv[0], dtls_package_version());
310 exit(1);
311 }
312 }
313
314 dtls_set_log_level(log_level);
315
316 /* init socket and set it to non-blocking */
317 fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
318
319 if (fd < 0) {
320 dtls_alert("socket: %s\n", strerror(errno));
321 return 0;
322 }
323
324 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
325 dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
326 }
327 #if 0
328 flags = fcntl(fd, F_GETFL, 0);
329 if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
330 dtls_alert("fcntl: %s\n", strerror(errno));
331 goto error;
332 }
333 #endif
334 on = 1;
335 #ifdef IPV6_RECVPKTINFO
336 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
337 #else /* IPV6_RECVPKTINFO */
338 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
339 #endif /* IPV6_RECVPKTINFO */
340 dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
341 }
342
343 if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
344 dtls_alert("bind: %s\n", strerror(errno));
345 goto error;
346 }
347
348 dtls_init();
349
350 the_context = dtls_new_context(&fd);
351
352 dtls_set_handler(the_context, &cb);
353
354 while (1) {
355 FD_ZERO(&rfds);
356 FD_ZERO(&wfds);
357
358 FD_SET(fd, &rfds);
359 /* FD_SET(fd, &wfds); */
360
361 timeout.tv_sec = 5;
362 timeout.tv_usec = 0;
363
364 result = select( fd+1, &rfds, &wfds, 0, &timeout);
365
366 if (result < 0) { /* error */
367 if (errno != EINTR)
368 perror("select");
369 } else if (result == 0) { /* timeout */
370 } else { /* ok */
371 if (FD_ISSET(fd, &wfds))
372 ;
373 else if (FD_ISSET(fd, &rfds)) {
374 dtls_handle_read(the_context);
375 }
376 }
377 }
378
379 error:
380 dtls_free_context(the_context);
381 exit(0);
382 }
383