/net/ip/tinydtls/tests/secure-server.c
C | 862 lines | 670 code | 132 blank | 60 comment | 125 complexity | 8d616f4ac6679dfb9ab6a5fdc853a340 MD5 | raw file
- /* secure-server -- A (broken) DTLS server example
- *
- * Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org>
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/select.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <signal.h>
- #include <openssl/ssl.h>
- #include <openssl/bio.h>
- #include <openssl/err.h>
- #include <openssl/rand.h>
- #ifdef WITH_DTLS
- #define SERVER_CERT_PEM "./server-cert.pem"
- #define SERVER_KEY_PEM "./server-key.pem"
- #define CA_CERT_PEM "./ca-cert.pem"
- #endif
- #ifdef HAVE_ASSERT_H
- # include <assert.h>
- #else
- # define assert(x)
- #endif /* HAVE_ASSERT_H */
- static int quit=0;
- /* SIGINT handler: set quit to 1 for graceful termination */
- void
- handle_sigint(int signum) {
- quit = 1;
- }
- int
- check_connect(int sockfd, char *buf, int buflen,
- struct sockaddr *src, int *ifindex) {
- /* for some reason, the definition in netinet/in.h is not exported */
- #ifndef IN6_PKTINFO
- struct in6_pktinfo
- {
- struct in6_addr ipi6_addr; /* src/dst IPv6 address */
- unsigned int ipi6_ifindex; /* send/recv interface index */
- };
- #endif
- size_t bytes;
- struct iovec iov[1] = { {buf, buflen} };
- char cmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- struct in6_pktinfo *p = NULL;
-
- struct msghdr msg = { 0 };
- struct cmsghdr *cmsg;
- msg.msg_name = src;
- msg.msg_namelen = sizeof(struct sockaddr_in6);
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = sizeof(cmsgbuf);
- bytes = recvmsg(sockfd, &msg, MSG_DONTWAIT | MSG_PEEK);
- if (bytes < 0) {
- perror("recvmsg");
- return bytes;
- }
- /* TODO: handle msg.msg_flags & MSG_TRUNC */
- if (msg.msg_flags & MSG_CTRUNC) {
- fprintf(stderr, "control was truncated!\n");
- return -1;
- }
- if (ifindex) {
- /* Here we try to retrieve the interface index where the packet was received */
- *ifindex = 0;
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
- p = (struct in6_pktinfo *)(CMSG_DATA(cmsg));
- *ifindex = p->ipi6_ifindex;
- break;
- }
- }
- }
- return bytes;
- }
- typedef enum { UNKNOWN=0, DTLS=1 } protocol_t;
- protocol_t
- demux_protocol(const char *buf, int len) {
- return DTLS;
- }
- #ifdef WITH_DTLS
- typedef enum {
- PEER_ST_ESTABLISHED, PEER_ST_PENDING, PEER_ST_CLOSED
- } peer_state_t;
- typedef struct {
- peer_state_t state;
- unsigned long h;
- SSL *ssl;
- } ssl_peer_t;
- #define MAX_SSL_PENDING 2 /* must be less than MAX_SSL_PEERS */
- #define MAX_SSL_PEERS 10 /* MAX_SSL_PENDING of these might be pending */
- ssl_peer_t *ssl_peer_storage[MAX_SSL_PEERS];
- static int pending = 0;
- void
- check_peers() {
- typedef struct bio_dgram_data_st
- {
- union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
- struct sockaddr_in6 sa_in6;
- } peer;
- unsigned int connected;
- unsigned int _errno;
- unsigned int mtu;
- struct timeval next_timeout;
- struct timeval socket_timeout;
- } bio_dgram_data;
- struct sockaddr_in6 peer;
- int i;
- BIO *bio;
- for (i = 0; i < MAX_SSL_PEERS; i++) {
- if (ssl_peer_storage[i]) {
- if (!ssl_peer_storage[i]->ssl)
- fprintf(stderr, "invalid SSL object for peer %d!\n",i);
- else {
- bio = SSL_get_rbio(ssl_peer_storage[i]->ssl);
- if (bio) {
- (void) BIO_dgram_get_peer(bio, (struct sockaddr *)&peer);
- if (peer.sin6_port && ssl_peer_storage[i]->h != ntohs(peer.sin6_port)) {
- fprintf(stderr, " bio %p: port differs from hash: %d != %d! (%sconnected)\n", bio,
- ssl_peer_storage[i]->h,
- ntohs(((struct sockaddr_in6 *)&peer)->sin6_port),
- ((bio_dgram_data *)bio->ptr)->connected ? "" : "not ");
- }
- }
- }
- }
- }
- }
- /** Creates a hash value from the first num bytes of s, taking init as
- * initialization value. */
- static inline unsigned long
- _hash(unsigned long init, const char *s, int num) {
- int c;
- while (num--)
- while ( (c = *s++) ) {
- init = ((init << 7) + init) + c;
- }
- return init;
- }
- static inline unsigned long
- hash_peer(const struct sockaddr *peer, int ifindex) {
- unsigned long h;
- /* initialize hash value to interface index */
- h = _hash(0, (char *)&ifindex, sizeof(int));
- #define CAST(TYPE,VAR) ((TYPE)VAR)
- assert(peer);
- switch (peer->sa_family) {
- case AF_INET:
- return ntohs(CAST(const struct sockaddr_in *, peer)->sin_port);
- h = _hash(h, (char *) &CAST(const struct sockaddr_in *, peer)->sin_addr,
- sizeof(struct in_addr));
- h = _hash(h, (char *) &CAST(const struct sockaddr_in *, peer)->sin_port,
- sizeof(in_port_t));
- break;
- case AF_INET6:
- return ntohs(CAST(const struct sockaddr_in6 *, peer)->sin6_port);
- h = _hash(h,
- (char *) &CAST(const struct sockaddr_in6 *, peer)->sin6_addr,
- sizeof(struct in6_addr));
- h = _hash(h,
- (char *) &CAST(const struct sockaddr_in6 *, peer)->sin6_port,
- sizeof(in_port_t));
- break;
- default:
- /* last resort */
- h = _hash(h, (char *)peer, sizeof(struct sockaddr));
- }
- return 42;
- return h;
- }
- /* Returns index of peer object for specified address/ifindex pair. */
- int
- get_index_of_peer(const struct sockaddr *peer, int ifindex) {
- unsigned long h;
- int idx;
- #ifndef NDEBUG
- char addr[INET6_ADDRSTRLEN];
- char port[6];
- #endif
- if (!peer)
- return -1;
- h = hash_peer(peer,ifindex);
- for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
- if (ssl_peer_storage[idx] && ssl_peer_storage[idx]->h == h) {
- #ifndef NDEBUG
- getnameinfo((struct sockaddr *)peer, sizeof(struct sockaddr_in6),
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV);
- fprintf(stderr, "get_index_of_peer: [%s]:%s => %lu\n",
- addr, port, h);
- #endif
- return idx;
- }
- }
- return -1;
- }
- SSL *
- get_ssl(SSL_CTX *ctx, int sockfd, struct sockaddr *src, int ifindex) {
- int idx;
- BIO *bio;
- SSL *ssl;
- #ifndef NDEBUG
- struct sockaddr_storage peer;
- char addr[INET6_ADDRSTRLEN];
- char port[6];
- int i;
- #endif
- idx = get_index_of_peer(src,ifindex);
- if (idx >= 0) {
- fprintf(stderr,"found peer %d ",idx);
- switch (ssl_peer_storage[idx]->state) {
- case PEER_ST_ESTABLISHED: fprintf(stderr,"established\n"); break;
- case PEER_ST_PENDING: fprintf(stderr,"pending\n"); break;
- case PEER_ST_CLOSED: fprintf(stderr,"closed\n"); break;
- default:
- OPENSSL_assert(0);
- }
- #ifndef NDEBUG
- memset(&peer, 0, sizeof(peer));
- (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer);
- getnameinfo((struct sockaddr *)&peer, sizeof(peer),
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV);
- fprintf(stderr," [%s]:%s \n", addr, port);
- #endif
- return ssl_peer_storage[idx]->ssl;
- }
- /* none found, create new if sufficient space available */
- if (pending < MAX_SSL_PENDING) {
- for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
- if (ssl_peer_storage[idx] == NULL) { /* found space */
- ssl = SSL_new(ctx);
-
- if (ssl) {
- bio = BIO_new_dgram(sockfd, BIO_NOCLOSE);
- if (!bio) {
- SSL_free(ssl);
- return NULL;
- }
-
- SSL_set_bio(ssl, bio, bio);
- SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
-
- SSL_set_accept_state(ssl);
- ssl_peer_storage[idx] = (ssl_peer_t *) malloc(sizeof(ssl_peer_t));
- if (!ssl_peer_storage[idx]) {
- SSL_free(ssl);
- return NULL;
- }
- ssl_peer_storage[idx]->state = PEER_ST_PENDING;
- ssl_peer_storage[idx]->h = hash_peer(src,ifindex);
- ssl_peer_storage[idx]->ssl = ssl;
-
- pending++;
-
- fprintf(stderr,
- "created new SSL peer %d for ssl object %p (storage: %p)\n",
- idx, ssl, ssl_peer_storage[idx]);
- #ifndef NDEBUG
- if (getnameinfo((struct sockaddr *)&src, sizeof(src),
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
- perror("getnameinfo");
- fprintf(stderr, "port was %u\n", ntohs(((struct sockaddr_in6 *)src)->sin6_port));
- } else {
- fprintf(stderr," [%s]:%s \n", addr, port);
- }
- #endif
- OPENSSL_assert(ssl_peer_storage[idx]->ssl == ssl);
- fprintf(stderr,"%d objects pending\n", pending);
- check_peers();
- return ssl;
- }
- }
- }
- } else {
- fprintf(stderr, "too many pending SSL objects\n");
- return NULL;
- }
- fprintf(stderr, "too many peers\n");
- return NULL;
- }
- /** Deletes peer stored at index idx and frees allocated memory. */
- static inline void
- delete_peer(int idx) {
- if (idx < 0 || !ssl_peer_storage[idx])
- return;
- if (ssl_peer_storage[idx]->state == PEER_ST_PENDING)
- pending--;
- OPENSSL_assert(ssl_peer_storage[idx]->ssl);
- SSL_free(ssl_peer_storage[idx]->ssl);
-
- free(ssl_peer_storage[idx]);
- ssl_peer_storage[idx] = NULL;
- printf("deleted peer %d\n",idx);
- }
- /** Deletes all closed objects from ssl_peer_storage. */
- void
- remove_closed() {
- int idx;
- for (idx = 0; idx < MAX_SSL_PEERS; idx++)
- if (ssl_peer_storage[idx]
- && ssl_peer_storage[idx]->state == PEER_ST_CLOSED)
- delete_peer(idx);
- }
- #define min(a,b) ((a) < (b) ? (a) : (b))
- unsigned int
- psk_server_callback(SSL *ssl, const char *identity,
- unsigned char *psk, unsigned int max_psk_len) {
- static char keybuf[] = "secretPSK";
- printf("psk_server_callback: check identity of client %s\n", identity);
- memcpy(psk, keybuf, min(strlen(keybuf), max_psk_len));
- return min(strlen(keybuf), max_psk_len);
- }
- #endif
- #ifdef WITH_DTLS
- /**
- * This function tracks the status changes from libssl to manage local
- * object state.
- */
- void
- info_callback(const SSL *ssl, int where, int ret) {
- int idx, i;
- struct sockaddr_storage peer;
- struct sockaddr_storage peer2;
- char addr[INET6_ADDRSTRLEN];
- char port[6];
- if (where & SSL_CB_LOOP) /* do not care for intermediary states */
- return;
- memset(&peer, 0, sizeof(peer));
- (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
- /* lookup SSL object */ /* FIXME: need to get the ifindex */
- idx = get_index_of_peer((struct sockaddr *)&peer, 0);
-
- if (idx >= 0)
- fprintf(stderr, "info_callback: assert: %d < 0 || %p == %p (storage: %p)\n",
- idx, ssl, ssl_peer_storage[idx]->ssl, ssl_peer_storage[idx]);
- if (idx >= 0 && ssl != ssl_peer_storage[idx]->ssl) {
- getnameinfo((struct sockaddr *)&peer, sizeof(peer),
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV);
- fprintf(stderr," ssl: [%s]:%s ", addr, port);
-
- (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer2);
- getnameinfo((struct sockaddr *)&peer2, sizeof(peer2),
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV);
- fprintf(stderr," ssl_peer_storage[idx]->ssl: [%s]:%s\n", addr, port);
- fprintf(stderr, " hash:%lu h: %lu\n",
- hash_peer((const struct sockaddr *)&peer, 0),
- ssl_peer_storage[idx]->h);
- for (i = 0; i < MAX_SSL_PEERS; i++) {
- if (ssl_peer_storage[i]) {
- fprintf(stderr, "%02d: %p ssl: %p ",
- i, ssl_peer_storage[i] ,ssl_peer_storage[i]->ssl);
- (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[i]->ssl), &peer2);
- getnameinfo((struct sockaddr *)&peer2, sizeof(peer2),
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV);
-
- fprintf(stderr," peer: [%s]:%s h: %lu\n", addr, port, ssl_peer_storage[i]->h);
- }
- }
- fprintf(stderr, "***** ASSERT FAILED ******\n");
- memset(&peer, 0, sizeof(peer));
- (void) BIO_dgram_get_peer(SSL_get_wbio(ssl), &peer);
- idx = get_index_of_peer((struct sockaddr *)&peer, 0);
- fprintf(stderr, " get_index_of_peer for wbio returns %d, type is %04x\n",
- idx, where);
- }
- #if 1
- check_peers();
- OPENSSL_assert((idx < 0) || (ssl == ssl_peer_storage[idx]->ssl));
- #endif
- if (where & SSL_CB_ALERT) {
- #ifndef NDEBUG
- if (ret != 0)
- fprintf(stderr,"%s:%s:%s\n", SSL_alert_type_string(ret),
- SSL_alert_desc_string(ret), SSL_alert_desc_string_long(ret));
- #endif
- /* examine alert type */
- switch (*SSL_alert_type_string(ret)) {
- case 'F':
- /* move SSL object from pending to close */
- if (idx >= 0) {
- ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
- pending--;
- }
- break;
- case 'W':
- if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) {
- if (where == SSL_CB_WRITE_ALERT)
- fprintf(stderr,"sent CLOSE_NOTIFY\n");
- else /* received CN */
- fprintf(stderr,"received CLOSE_NOTIFY\n");
- }
- break;
- default: /* handle unknown alert types */
- #ifndef NDEBUG
- printf("not handled!\n");
- #endif
- }
- }
- if (where & SSL_CB_HANDSHAKE_DONE) {
- /* move SSL object from pending to established */
- printf("HANDSHAKE_DONE ");
- if (idx >= 0) {
-
- if (ssl_peer_storage[idx]->state == PEER_ST_PENDING) {
- ssl_peer_storage[idx]->state = PEER_ST_ESTABLISHED;
- pending--;
- printf("moved SSL object %d to ESTABLISHED\n", idx);
- printf("%d objects pending\n", pending);
- } else {
- #ifndef NDEBUG
- printf("huh, object %d was not pending? (%d)\n", idx,
- ssl_peer_storage[idx]->state);
- #endif
- }
- return;
- }
- return;
- }
- return;
- }
- #endif
- #ifdef WITH_DTLS
- /* checks if ssl object was closed and can be removed */
- int
- check_close(SSL *ssl) {
- int res, err, idx;
- struct sockaddr_storage peer;
-
- memset(&peer, 0, sizeof(peer));
- (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
- res = 0;
- if (SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) {
- printf("SSL_RECEIVED_SHUTDOWN\n");
- res = SSL_shutdown(ssl);
- if (res == 0) {
- printf("must call SSL_shutdown again\n");
- res = SSL_shutdown(ssl);
- }
- if (res < 0) {
- err = SSL_get_error(ssl,res);
- fprintf(stderr, "shutdown: SSL error %d: %s\n", err,
- ERR_error_string(err, NULL));
- }
- /* we can close the SSL object anyway */
- /* FIXME: need to get ifindex from somewhere */
- idx = get_index_of_peer((struct sockaddr *)&peer, 0);
- OPENSSL_assert(idx < 0 || ssl == ssl_peer_storage[idx]->ssl);
- if (idx >= 0) {
- ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
- printf("moved SSL object %d to CLOSED\n",idx);
- }
- }
-
- return res;
- }
- int
- check_timeout() {
- int i, result, err;
- for (i = 0; i < MAX_SSL_PEERS; i++) {
- if (ssl_peer_storage[i]) {
- OPENSSL_assert(ssl_peer_storage[i]->ssl);
- result = DTLSv1_handle_timeout(ssl_peer_storage[i]->ssl);
- if (result < 0) {
- err = SSL_get_error(ssl_peer_storage[i]->ssl,result);
- fprintf(stderr, "dtls1_handle_timeout (%d): %s\n",
- err, ERR_error_string(err, NULL));
- }
- }
- }
- /* remove outdated obbjects? */
-
- return 0;
- }
- #endif /* WITH_DTLS */
-
- int
- _read(SSL_CTX *ctx, int sockfd) {
- char buf[2000];
- struct sockaddr_in6 src;
- int len, ifindex, i;
- char addr[INET6_ADDRSTRLEN];
- char port[6];
- socklen_t sz = sizeof(struct sockaddr_in6);
- #ifdef WITH_DTLS
- SSL *ssl;
- int err;
- #endif
- /* Retrieve remote address and interface index as well as the first
- few bytes of the message to demultiplex protocols. */
- memset(&src, 0, sizeof(struct sockaddr_in6));
- len = check_connect(sockfd, buf, 4, (struct sockaddr *)&src, &ifindex);
- if (len < 0) /* error */
- return len;
- #ifndef NDEBUG
- fprintf(stderr,"received packet");
-
- if (getnameinfo((struct sockaddr *)&src, sizeof(src),
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV) == 0)
- fprintf(stderr," from [%s]:%s", addr, port);
-
- fprintf(stderr," on interface %d\n", ifindex);
- #endif
- switch (demux_protocol(buf, len)) {
- #ifdef WITH_DTLS
- case DTLS :
- ssl = get_ssl(ctx, sockfd, (struct sockaddr *)&src, ifindex);
- if (!ssl) {
- fprintf(stderr, "cannot create new SSL object\n");
- /* return recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT);*/
- len = recvfrom(sockfd, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *)&src, &sz);
- getnameinfo((struct sockaddr *)&src, sz,
- addr, sizeof(addr), port, sizeof(port),
- NI_NUMERICHOST | NI_NUMERICSERV);
- printf("discarded %d bytes from [%s]:%s\n", len, addr, port);
- return len;
- }
- len = SSL_read(ssl, buf, sizeof(buf));
- break;
- #endif
- case UNKNOWN:
- default :
- len = recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT);
- }
- if (len > 0) {
- printf("here is the data:\n");
- for (i=0; i<len; i++)
- printf("%c",buf[i]);
- } if (len == 0) { /* session closed? */
- #ifdef WITH_DTLS
- if (check_close(ssl) <= 0) {
- fprintf(stderr, "not closed\n");
- }
- #endif
- } else {
- #ifdef WITH_DTLS
- err = SSL_get_error(ssl,len);
- switch (err) {
- case SSL_ERROR_WANT_READ:
- fprintf(stderr, "SSL_ERROR_WANT_READ\n");
- return 0;
- case SSL_ERROR_WANT_WRITE:
- fprintf(stderr, "SSL_ERROR_WANT_WRITE\n");
- return 0;
- default:
- fprintf(stderr, "read: SSL error %d: %s\n", err,
- ERR_error_string(err, NULL));
- return 0;
- }
- #else
- perror("recv");
- #endif
- }
- return len;
- }
- int
- _write(SSL_CTX *ctx, int sockfd) {
- int res = 0;
- #ifdef WITH_DTLS
- SSL *ssl;
- int err;
- ssl = get_ssl(ctx, sockfd, NULL, 1);
- if (!ssl) {
- fprintf(stderr, "no SSL object for writing");
- return 0;
- }
- res = SSL_write(ssl, NULL, 0);
- if (res < 0) {
- /*
- if (SSL_want_write(ssl))
- return 0;
- */
- /* FIXME: check SSL_want_read(ssl) */
- err = SSL_get_error(ssl,res);
- fprintf(stderr,"SSL_write returned %d (%s)\n", err, ERR_error_string(err, NULL));
- } else {
- printf("SSL_write successful\n");
- }
- #else
- #endif
-
- return res;
- }
- int
- generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) {
- /* FIXME: generate secure client-specific cookie */
- #define DUMMYSTR "ABCDEFGHIJKLMNOP"
- *cookie_len = strlen(DUMMYSTR);
- memcpy(cookie, DUMMYSTR, *cookie_len);
- return 1;
- }
- int
- verify_cookie(SSL *ssl, unsigned char *cookie, unsigned int cookie_len) {
- /* FIXME */
- return 1;
- }
- enum { READ, WRITE };
- int
- main(int argc, char **argv) {
- int sockfd = 0;
- int on = 1;
- struct sockaddr_in6 listen_addr = { AF_INET6, htons(20220), 0, IN6ADDR_ANY_INIT, 0 };
- size_t addr_size = sizeof(struct sockaddr_in6);
- fd_set fds[2];
- int result, flags;
- int idx, res = 0;
- struct timeval timeout;
- struct sigaction act, oact;
-
- #ifdef WITH_DTLS
- SSL_CTX *ctx;
- memset(ssl_peer_storage, 0, sizeof(ssl_peer_storage));
- SSL_load_error_strings();
- SSL_library_init();
- ctx = SSL_CTX_new(DTLSv1_server_method());
- SSL_CTX_set_cipher_list(ctx, "ALL");
- SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
- res = SSL_CTX_use_certificate_file(ctx, SERVER_CERT_PEM, SSL_FILETYPE_PEM);
- if (res != 1) {
- fprintf(stderr, "cannot read server certificate from file '%s' (%s)\n",
- SERVER_CERT_PEM, ERR_error_string(res,NULL));
- goto end;
- }
- res = SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_PEM, SSL_FILETYPE_PEM);
- if (res != 1) {
- fprintf(stderr, "cannot read server key from file '%s' (%s)\n",
- SERVER_KEY_PEM, ERR_error_string(res,NULL));
- goto end;
- }
- res = SSL_CTX_check_private_key (ctx);
- if (res != 1) {
- fprintf(stderr, "invalid private key\n");
- goto end;
- }
- res = SSL_CTX_load_verify_locations(ctx, CA_CERT_PEM, NULL);
- if (res != 1) {
- fprintf(stderr, "cannot read ca file '%s'\n", CA_CERT_PEM);
- goto end;
- }
- /* Client has to authenticate */
- /* Client has to authenticate */
- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
- SSL_CTX_set_read_ahead(ctx, 1); /* disable read-ahead */
- SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
- SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie);
- SSL_CTX_use_psk_identity_hint(ctx, "Enter password for CoAP-Gateway");
- SSL_CTX_set_psk_server_callback(ctx, psk_server_callback);
- SSL_CTX_set_info_callback(ctx, info_callback);
- #endif
- sockfd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
- if ( sockfd < 0 ) {
- perror("socket");
- return -1;
- }
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0)
- perror("setsockopt SO_REUSEADDR");
- flags = fcntl(sockfd, F_GETFL, 0);
- if (flags < 0 || fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
- perror("fcntl");
- return -1;
- }
- on = 1;
- if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
- perror("setsockopt IPV6_PKTINFO");
- }
- if (bind (sockfd, (const struct sockaddr *)&listen_addr, addr_size) < 0) {
- perror("bind");
- res = -2;
- goto end;
- }
- act.sa_handler = handle_sigint;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- sigaction(SIGINT, &act, &oact);
- while (!quit) {
- FD_ZERO(&fds[READ]);
- FD_ZERO(&fds[WRITE]);
- FD_SET(sockfd, &fds[READ]);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
- result = select( FD_SETSIZE, &fds[READ], &fds[WRITE], 0, &timeout);
- if (result < 0) { /* error */
- if (errno != EINTR)
- perror("select");
- } else if (result > 0) { /* read from socket */
- if ( FD_ISSET( sockfd, &fds[READ]) ) {
- _read(ctx, sockfd); /* read received data */
- } else if ( FD_ISSET( sockfd, &fds[WRITE]) ) { /* write to socket */
- _write(ctx, sockfd); /* write data */
- }
- } else { /* timeout */
- check_timeout();
- }
- remove_closed();
- }
-
- end:
- #ifdef WITH_DTLS
- for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
- if (ssl_peer_storage[idx] && ssl_peer_storage[idx]->ssl) {
- if (ssl_peer_storage[idx]->state == PEER_ST_ESTABLISHED)
- SSL_shutdown(ssl_peer_storage[idx]->ssl);
- SSL_free(ssl_peer_storage[idx]->ssl);
- }
- }
- SSL_CTX_free(ctx);
- #endif
- close(sockfd); /* don't care if we close stdin at this point */
- return res;
- }