2 /* This is needed for apple */
3 #define __APPLE_USE_RFC_3542
10 #include <netinet/in.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
21 #define DEFAULT_PORT 20220
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};
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};
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};
42 /* SIGINT handler: set quit to 1 for graceful termination */
44 handle_sigint(int signum) {
45 dsrv_stop(dsrv_get_context());
51 #define PSK_SERVER_HINT "Server_identity"
53 /* This function is the "key store" for tinyDTLS. It is called to
54 * retrieve a key for the given identity within this particular
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) {
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 }
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);
83 memcpy(result, PSK_SERVER_HINT, strlen(PSK_SERVER_HINT));
84 return strlen(PSK_SERVER_HINT);
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);
96 memcpy(result, psk[i].key, psk[i].key_length);
97 return psk[i].key_length;
104 dtls_warn("unsupported request type: %d\n", type);
107 return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
110 #endif /* DTLS_PSK */
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
124 *result = &ecdsa_key;
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,
136 #endif /* DTLS_ECC */
138 #define DTLS_SERVER_CMD_CLOSE "server:close"
139 #define DTLS_SERVER_CMD_RENEGOTIATE "server:renegotiate"
142 read_from_peer(struct dtls_context_t *ctx,
143 session_t *session, uint8 *data, size_t len) {
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);
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);
159 return dtls_write(ctx, session, data, len);
163 send_to_peer(struct dtls_context_t *ctx,
164 session_t *session, uint8 *data, size_t len) {
166 int fd = *(int *)dtls_get_app_data(ctx);
167 return sendto(fd, data, len, MSG_DONTWAIT,
168 &session->addr.sa, session->size);
172 dtls_handle_read(struct dtls_context_t *ctx) {
175 static uint8 buf[DTLS_MAX_BUF];
178 fd = dtls_get_app_data(ctx);
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);
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));
198 return dtls_handle_message(ctx, &session, buf, len);
202 resolve_address(const char *server, struct sockaddr *dst) {
204 struct addrinfo *res, *ainfo;
205 struct addrinfo hints;
206 static char addrstr[256];
209 memset(addrstr, 0, sizeof(addrstr));
210 if (server && strlen(server) > 0)
211 memcpy(addrstr, server, strlen(server));
213 memcpy(addrstr, "localhost", 9);
215 memset ((char *)&hints, 0, sizeof(hints));
216 hints.ai_socktype = SOCK_DGRAM;
217 hints.ai_family = AF_UNSPEC;
219 error = getaddrinfo(addrstr, "", &hints, &res);
222 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
226 for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
228 switch (ainfo->ai_family) {
231 memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
232 return ainfo->ai_addrlen;
243 usage(const char *program, const char *version) {
246 p = strrchr( program, '/' );
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_256\n"
258 "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n",
259 program, version, program, DEFAULT_PORT);
262 static dtls_handler_t cb = {
263 .write = send_to_peer,
264 .read = read_from_peer,
267 .get_psk_info = get_psk_info,
268 #endif /* DTLS_PSK */
270 .get_ecdsa_key = get_ecdsa_key,
271 .verify_ecdsa_key = verify_ecdsa_key
272 #endif /* DTLS_ECC */
276 main(int argc, char **argv) {
277 dtls_context_t *the_context = NULL;
278 log_t log_level = DTLS_LOG_WARN;
280 struct timeval timeout;
283 dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
284 struct sockaddr_in6 listen_addr;
286 memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
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);
293 listen_addr.sin6_family = AF_INET6;
294 listen_addr.sin6_port = htons(DEFAULT_PORT);
295 listen_addr.sin6_addr = in6addr_any;
297 while ((opt = getopt(argc, argv, "A:p:v:a:")) != -1) {
300 if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) {
301 fprintf(stderr, "cannot resolve address\n");
306 listen_addr.sin6_port = htons(atoi(optarg));
309 log_level = strtol(optarg, NULL, 10);
312 if( strcmp(optarg, "enable") == 0)
313 ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
316 usage(argv[0], dtls_package_version());
321 dtls_set_log_level(log_level);
323 /* init socket and set it to non-blocking */
324 fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
327 dtls_alert("socket: %s\n", strerror(errno));
331 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
332 dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
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));
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));
350 if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
351 dtls_alert("bind: %s\n", strerror(errno));
357 the_context = dtls_new_context(&fd);
359 /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */
360 dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe);
362 dtls_set_handler(the_context, &cb);
369 /* FD_SET(fd, &wfds); */
374 result = select( fd+1, &rfds, &wfds, 0, &timeout);
376 if (result < 0) { /* error */
379 } else if (result == 0) { /* timeout */
381 if (FD_ISSET(fd, &wfds))
383 else if (FD_ISSET(fd, &rfds)) {
384 dtls_handle_read(the_context);
390 dtls_free_context(the_context);