diff --git a/dtls/Makefile b/dtls/Makefile index 0d323dd2..b3fc145d 100644 --- a/dtls/Makefile +++ b/dtls/Makefile @@ -2,7 +2,7 @@ CC=gcc CFLAGS=-Wall -DWOLFSSL_DTLS LIBS=-lwolfssl -lpthread -all: client-udp client-dtls client-dtls-nonblocking client-dtls-resume client-dtls-shared server-udp server-dtls server-dtls-nonblocking server-dtls-threaded client-dtls-ipv6 server-dtls-ipv6 +all: client-udp client-dtls client-dtls-nonblocking client-dtls-resume client-dtls-shared server-udp server-dtls server-dtls-nonblocking server-dtls-threaded client-dtls-ipv6 server-dtls-ipv6 client-dtls-callback server-dtls-callback client-udp: client-udp.o $(CC) -o $@ $^ $(CFLAGS) @@ -37,7 +37,13 @@ server-dtls-nonblocking: server-dtls-nonblocking.o server-dtls-threaded: server-dtls-threaded.o $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +client-dtls-callback: client-dtls-callback.o + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + +server-dtls-callback: server-dtls-callback.o + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + .PHONY: clean all clean: - rm -f *.o client-udp client-dtls client-dtls-nonblocking client-dtls-resume client-dtls-shared server-udp server-dtls server-dtls-nonblocking server-dtls-threaded server-dtls-ipv6 client-dtls-ipv6 + rm -f *.o client-udp client-dtls client-dtls-nonblocking client-dtls-resume client-dtls-shared server-udp server-dtls server-dtls-nonblocking server-dtls-threaded server-dtls-ipv6 client-dtls-ipv6 client-dtls-callback server-dtls-callback diff --git a/dtls/client-dtls-callback.c b/dtls/client-dtls-callback.c new file mode 100644 index 00000000..0d9418f2 --- /dev/null +++ b/dtls/client-dtls-callback.c @@ -0,0 +1,281 @@ +/* + * client-dtls-callback.c + * + * Copyright (C) 2006-2015 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + *============================================================================= + * + * Bare-bones example of a DTLS client for instructional/learning purposes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXLINE 4096 +#define SERV_PORT 11111 + +typedef struct SharedDtls { + WOLFSSL* ssl; /* WOLFSSL object being shared */ + int sd; /* socket fd */ + struct sockaddr_in servAddr; /* server sockaddr */ + socklen_t servSz; /* length of servAddr */ + char* recvBuf; /* I/O recv cb buffer */ + int recvSz; /* bytes in recvBuf */ + int handShakeDone; /* is the handshake done? */ +} SharedDtls; + + +int my_IORecv(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + SharedDtls* shared = (SharedDtls*)ctx; + int recvd; + + printf("my_IORecv sz %d\n", sz); + + + /* Receive message from socket */ + recvd = recvfrom(shared->sd, buff, sz, 0, NULL, NULL); + if (recvd == -1) { + /* error encountered. Be responsible and report it in wolfSSL terms */ + + fprintf(stderr, "IO RECEIVE ERROR: "); + switch (errno) { + #if EAGAIN != EWOULDBLOCK + case EAGAIN: /* EAGAIN == EWOULDBLOCK on some systems, but not others */ + #endif + case EWOULDBLOCK: + if (!wolfSSL_dtls(ssl) || wolfSSL_get_using_nonblock(ssl)) { + fprintf(stderr, "would block\n"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + fprintf(stderr, "socket timeout\n"); + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + case ECONNRESET: + fprintf(stderr, "connection reset\n"); + return WOLFSSL_CBIO_ERR_CONN_RST; + case EINTR: + fprintf(stderr, "socket interrupted\n"); + return WOLFSSL_CBIO_ERR_ISR; + case ECONNREFUSED: + fprintf(stderr, "connection refused\n"); + return WOLFSSL_CBIO_ERR_WANT_READ; + case ECONNABORTED: + fprintf(stderr, "connection aborted\n"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + default: + fprintf(stderr, "general error\n"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else if (recvd == 0) { + printf("Connection closed\n"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + + printf("my_IORecv recvd %d \n", recvd); + + /* successful receive */ + printf("my_IORecv: received %d bytes from %d\n", sz, shared->sd); + return recvd; +} + + +int my_IOSend(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + SharedDtls* shared = (SharedDtls*)ctx; + int sent; + + printf("my_IOSend sz %d\n", sz); + + + sent = sendto(shared->sd, buff, sz, 0, + (const struct sockaddr*)&shared->servAddr, shared->servSz); + /* Send message to socket */ + if (sent == -1) { + /* error encountered. Be responsible and report it in wolfSSL terms */ + + fprintf(stderr, "IO SEND ERROR: "); + switch (errno) { + #if EAGAIN != EWOULDBLOCK + case EAGAIN: /* EAGAIN == EWOULDBLOCK on some systems, but not others */ + #endif + case EWOULDBLOCK: + fprintf(stderr, "would block\n"); + return WOLFSSL_CBIO_ERR_WANT_READ; + case ECONNRESET: + fprintf(stderr, "connection reset\n"); + return WOLFSSL_CBIO_ERR_CONN_RST; + case EINTR: + fprintf(stderr, "socket interrupted\n"); + return WOLFSSL_CBIO_ERR_ISR; + case EPIPE: + fprintf(stderr, "socket EPIPE\n"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + default: + fprintf(stderr, "general error\n"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else if (sent == 0) { + printf("Connection closed\n"); + return 0; + } + + printf("my_IOSend sent %d\n", sent); + + /* successful send */ + printf("my_IOSend: sent %d bytes to %d\n", sz, shared->sd); + return sent; +} + + +int main (int argc, char** argv) +{ + /* standard variables used in a dtls client*/ + int n = 0; + int sockfd = 0; + int err1; + int readErr; + //struct sockaddr_in servAddr; + WOLFSSL* ssl = 0; + WOLFSSL_CTX* ctx = 0; + char cert_array[] = "../certs/ca-cert.pem"; + char* certs = cert_array; + char sendLine[MAXLINE]; + char recvLine[MAXLINE - 1]; + SharedDtls shared; + + /* Program argument checking */ + if (argc != 2) { + printf("usage: udpcli \n"); + return 1; + } + + wolfSSL_Debugging_ON(); + + /* Initialize wolfSSL before assigning ctx */ + wolfSSL_Init(); + + + if ( (ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())) == NULL) { + fprintf(stderr, "wolfSSL_CTX_new error.\n"); + return 1; + } + + /* Register callbacks */ + wolfSSL_CTX_SetIORecv(ctx, my_IORecv); + wolfSSL_CTX_SetIOSend(ctx, my_IOSend); + + + /* Load certificates into ctx variable */ + if (wolfSSL_CTX_load_verify_locations(ctx, certs, 0) + != SSL_SUCCESS) { + fprintf(stderr, "Error loading %s, please check the file.\n", certs); + return 1; + } + + /* Assign ssl variable */ + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + printf("unable to get ssl object"); + return 1; + } + + + /* servAddr setup */ + memset(&shared.servAddr, 0, sizeof(shared.servAddr)); + shared.servAddr.sin_family = AF_INET; + shared.servAddr.sin_port = htons(SERV_PORT); + if (inet_pton(AF_INET, argv[1], &shared.servAddr.sin_addr) < 1) { + printf("Error and/or invalid IP address"); + return 1; + } + + if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("cannot create a socket."); + return 1; + } + + shared.sd = sockfd; + shared.servSz = sizeof(shared.servAddr); + shared.ssl = ssl; + shared.handShakeDone = 0; + + wolfSSL_SetIOWriteCtx(ssl, &shared); + wolfSSL_SetIOReadCtx(ssl, &shared); + + //wolfSSL_dtls_set_peer(ssl, &servAddr, sizeof(servAddr)); + + /* Set the file descriptor for ssl and connect with ssl variable */ + //wolfSSL_set_fd(ssl, sockfd); + if (wolfSSL_connect(ssl) != SSL_SUCCESS) { + err1 = wolfSSL_get_error(ssl, 0); + printf("err = %d, %s\n", err1, wolfSSL_ERR_reason_error_string(err1)); + printf("SSL_connect failed"); + return 1; + } + +/*****************************************************************************/ +/* Code for sending datagram to server */ + /* Loop until the user is finished */ + while (fgets(sendLine, MAXLINE, stdin) != NULL) { + + /* Send sendLine to the server */ + if ( ( wolfSSL_write(ssl, sendLine, strlen(sendLine))) + != strlen(sendLine)) { + printf("SSL_write failed"); + } + + /* n is the # of bytes received */ + n = wolfSSL_read(ssl, recvLine, sizeof(recvLine)-1); + + if (n < 0) { + readErr = wolfSSL_get_error(ssl, 0); + if (readErr != SSL_ERROR_WANT_READ) { + printf("wolfSSL_read failed"); + } + } + + /* Add a terminating character to the generic server message */ + recvLine[n] = '\0'; + fputs(recvLine, stdout); + } +/* End code for sending datagram to server */ +/*****************************************************************************/ + + /* Housekeeping */ + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); + close(sockfd); + wolfSSL_CTX_free(ctx); + wolfSSL_Cleanup(); + + return 0; +} diff --git a/dtls/server-dtls-callback.c b/dtls/server-dtls-callback.c new file mode 100644 index 00000000..9130494b --- /dev/null +++ b/dtls/server-dtls-callback.c @@ -0,0 +1,365 @@ +/* server-dtls-callback.c + * + * Copyright (C) 2006-2015 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + *============================================================================= + * + * Bare-bones example of a DTLS server for instructional/learning purposes. + * Utilizes DTLS 1.2. + */ + +#include +#include /* standard in/out procedures */ +#include /* defines system calls */ +#include /* necessary for memset */ +#include +#include /* used for all socket calls */ +#include /* used for sockaddr_in */ +#include +#include +#include +#include +#include + +#define SERV_PORT 11111 /* define our server port number */ +#define MSGLEN 4096 + +static int cleanup; /* To handle shutdown */ +struct sockaddr_in servAddr; /* our server's address */ +struct sockaddr_in cliaddr; /* the client's address */ + +void sig_handler(const int sig); + +void sig_handler(const int sig) +{ + printf("\nSIGINT %d handled\n", sig); + cleanup = 1; + return; +} + +typedef struct SharedDtls { + WOLFSSL* ssl; /* WOLFSSL object being shared */ + int sd; /* socket fd */ + struct sockaddr_in servAddr; /* server sockaddr */ + socklen_t servSz; /* length of servAddr */ + char* recvBuf; /* I/O recv cb buffer */ + int recvSz; /* bytes in recvBuf */ + int handShakeDone; /* is the handshake done? */ +} SharedDtls; + + +int my_IORecv(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + SharedDtls* shared = (SharedDtls*)ctx; + int recvd; + + printf("Server Recv %d\n", sz); + + recvd = recvfrom(shared->sd, buff, sz, 0, NULL, NULL); + if (recvd == -1) { + /* error encountered. Be responsible and report it in wolfSSL terms */ + + fprintf(stderr, "IO RECEIVE ERROR: "); + switch (errno) { + #if EAGAIN != EWOULDBLOCK + case EAGAIN: /* EAGAIN == EWOULDBLOCK on some systems, but not others */ + #endif + case EWOULDBLOCK: + if (!wolfSSL_dtls(ssl) || wolfSSL_get_using_nonblock(ssl)) { + fprintf(stderr, "would block\n"); + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + fprintf(stderr, "socket timeout\n"); + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + case ECONNRESET: + fprintf(stderr, "connection reset\n"); + return WOLFSSL_CBIO_ERR_CONN_RST; + case EINTR: + fprintf(stderr, "socket interrupted\n"); + return WOLFSSL_CBIO_ERR_ISR; + case ECONNREFUSED: + fprintf(stderr, "connection refused\n"); + return WOLFSSL_CBIO_ERR_WANT_READ; + case ECONNABORTED: + fprintf(stderr, "connection aborted\n"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + default: + fprintf(stderr, "general error\n"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else if (recvd == 0) { + printf("Connection closed\n"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + + printf("Server Recvd %d\n", recvd); + + /* successful receive */ + printf("my_IORecv: received %d bytes from %d\n", sz, shared->sd); + return recvd; +} + +int my_IOSend(WOLFSSL* ssl, char* buff, int sz, void* ctx) +{ + SharedDtls* shared = (SharedDtls*)ctx; + int sent; + + printf("Server Send %d\n", sz); + + + sent = sendto(shared->sd, buff, sz, 0, + (const struct sockaddr*)&shared->servAddr, shared->servSz); + /* Send message to socket */ + if (sent == -1) { + /* error encountered. Be responsible and report it in wolfSSL terms */ + + fprintf(stderr, "IO SEND ERROR: "); + switch (errno) { + #if EAGAIN != EWOULDBLOCK + case EAGAIN: /* EAGAIN == EWOULDBLOCK on some systems, but not others */ + #endif + case EWOULDBLOCK: + fprintf(stderr, "would block\n"); + return WOLFSSL_CBIO_ERR_WANT_READ; + case ECONNRESET: + fprintf(stderr, "connection reset\n"); + return WOLFSSL_CBIO_ERR_CONN_RST; + case EINTR: + fprintf(stderr, "socket interrupted\n"); + return WOLFSSL_CBIO_ERR_ISR; + case EPIPE: + fprintf(stderr, "socket EPIPE\n"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + default: + fprintf(stderr, "general error\n"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else if (sent == 0) { + printf("Connection closed\n"); + return 0; + } + + printf("Server Sent %d\n", sent); + + /* successful send */ + printf("my_IOSend: sent %d bytes to %d\n", sz, shared->sd); + return sent; +} + + +int main(int argc, char** argv) +{ + /* cont short for "continue?", Loc short for "location" */ + int cont = 0; + char caCertLoc[] = "../certs/ca-cert.pem"; + char servCertLoc[] = "../certs/server-cert.pem"; + char servKeyLoc[] = "../certs/server-key.pem"; + WOLFSSL_CTX* ctx; + /* Variables for awaiting datagram */ + int on = 1; + int res = 1; + int connfd = 0; + int recvLen = 0; /* length of message */ + WOLFSSL* ssl = NULL; + socklen_t cliLen; + socklen_t len = sizeof(int); + unsigned char b[MSGLEN]; /* watch for incoming messages */ + char buff[MSGLEN]; /* the incoming message */ + char ack[] = "I hear you fashizzle!\n"; + int listenfd = 0; /* Initialize our socket */ + SharedDtls shared; + + /* Code for handling signals */ + struct sigaction act, oact; + act.sa_handler = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGINT, &act, &oact); + + /* "./config --enable-debug" and uncomment next line for debugging */ + wolfSSL_Debugging_ON(); + + /* Initialize wolfSSL */ + wolfSSL_Init(); + + /* Set ctx to DTLS 1.2 */ + if ((ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())) == NULL) { + printf("wolfSSL_CTX_new error.\n"); + return 1; + } + /* Load CA certificates */ + if (wolfSSL_CTX_load_verify_locations(ctx,caCertLoc,0) != + SSL_SUCCESS) { + printf("Error loading %s, please check the file.\n", caCertLoc); + return 1; + } + /* Load server certificates */ + if (wolfSSL_CTX_use_certificate_file(ctx, servCertLoc, SSL_FILETYPE_PEM) != + SSL_SUCCESS) { + printf("Error loading %s, please check the file.\n", servCertLoc); + return 1; + } + /* Load server Keys */ + if (wolfSSL_CTX_use_PrivateKey_file(ctx, servKeyLoc, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + printf("Error loading %s, please check the file.\n", servKeyLoc); + return 1; + } + + /* Register callbacks */ + wolfSSL_CTX_SetIORecv(ctx, my_IORecv); + wolfSSL_CTX_SetIOSend(ctx, my_IOSend); + + + /* Await Datagram */ + while (cleanup != 1) { + + /* Create a UDP/IP socket */ + if ((listenfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + printf("Cannot create socket.\n"); + cleanup = 1; + } + printf("Socket allocated\n"); + + /* clear servAddr each loop */ + memset((char *)&servAddr, 0, sizeof(servAddr)); + + /* host-to-network-long conversion (htonl) */ + /* host-to-network-short conversion (htons) */ + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(SERV_PORT); + + /* Eliminate socket already in use error */ + res = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, len); + if (res < 0) { + printf("Setsockopt SO_REUSEADDR failed.\n"); + cleanup = 1; + cont = 1; + } + + /*Bind Socket*/ + if (bind(listenfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0) { + printf("Bind failed.\n"); + cleanup = 1; + cont = 1; + } + + printf("Awaiting client connection on port %d\n", SERV_PORT); + + cliLen = sizeof(cliaddr); + connfd = (int)recvfrom(listenfd, (char *)&b, sizeof(b), MSG_PEEK, + (struct sockaddr*)&shared.servAddr, &cliLen); + + if (connfd < 0) { + printf("No clients in que, enter idle state\n"); + continue; + } + else if (connfd > 0) { + if (connect(listenfd, (const struct sockaddr *)&shared.servAddr, + sizeof(shared.servAddr)) != 0) { + printf("Udp connect failed.\n"); + cleanup = 1; + cont = 1; + } + } + else { + printf("Recvfrom failed.\n"); + cleanup = 1; + cont = 1; + } + printf("Connected!\n"); + + /* Create the WOLFSSL Object */ + if ((ssl = wolfSSL_new(ctx)) == NULL) { + printf("wolfSSL_new error.\n"); + cleanup = 1; + cont = 1; + } + + shared.sd = listenfd; + shared.servSz = sizeof(shared.servAddr); + shared.ssl = ssl; + shared.handShakeDone = 0; + + wolfSSL_SetIOWriteCtx(ssl, &shared); + wolfSSL_SetIOReadCtx(ssl, &shared); + + /* set the session ssl to client connection port */ + //wolfSSL_set_fd(ssl, listenfd); + + if (wolfSSL_accept(ssl) != SSL_SUCCESS) { + + int e = wolfSSL_get_error(ssl, 0); + + printf("error = %d, %s\n", e, wolfSSL_ERR_reason_error_string(e)); + printf("SSL_accept failed.\n"); + continue; + } + if ((recvLen = wolfSSL_read(ssl, buff, sizeof(buff)-1)) > 0) { + printf("heard %d bytes\n", recvLen); + + buff[recvLen] = 0; + printf("I heard this: \"%s\"\n", buff); + } + else if (recvLen < 0) { + int readErr = wolfSSL_get_error(ssl, 0); + if(readErr != SSL_ERROR_WANT_READ) { + printf("SSL_read failed.\n"); + cleanup = 1; + cont = 1; + } + } + if (wolfSSL_write(ssl, ack, sizeof(ack)) < 0) { + printf("wolfSSL_write fail.\n"); + cleanup = 1; + cont = 1; + } + else { + printf("Sending reply.\n"); + } + + printf("reply sent \"%s\"\n", ack); + + wolfSSL_set_fd(ssl, 0); + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); + + printf("Client left cont to idle state\n"); + cont = 0; + } + + /* With the "continue" keywords, it is possible for the loop to exit * + * without changing the value of cont */ + if (cleanup == 1) { + cont = 1; + } + + if (cont == 1) { + wolfSSL_CTX_free(ctx); + wolfSSL_Cleanup(); + } + + return 0; +} +