/**************************************************************************** File Name : wolfSSLServerTask.c Author : wolfSSL Inc. Date Created : March 25, 2016 Current Revision : 1.0 Notes : This file contains a simple TLS server task with the goal of demonstrating how the wolfSSL embedded SSL/TLS library can be used with the uTasker stack. This server creates a TCP socket, sets the socket to listening mode, and when a connection is received negotiates an SSL/TLS session with the peer. It expects the peer to send a simple message (ex: 'hello wolfssl!'), sends a simple message back in return ('I hear you fa shizzle!'), closes the session and socket, then loops back around to listen for another connection. Copyright (C) wolfSSL, Inc. 2020 *****************************************************************************/ #include "config.h" #include "wolfSSLServerTask.h" #include "wolfssl/wolfcrypt/settings.h" #include "wolfssl/wolfcrypt/aes.h" #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/ssl.h" #define TEST_BUFFER_LENGTH 100 #define MAX_TCP_LENGTH 1460 #define RECV_BUFFER_LENGTH 1500 /* ---------------------------- STRUCTS / ENUMS ---------------------------- */ typedef enum { serverInit = 0, serverSocketSetup = 1, serverIdle = 2, serverListening = 3, serverTLSInit = 4, serverTLSNew = 5, serverTLSAccept = 6, serverTLSSend = 7, serverTLSRecv = 8, serverShutdown = 9, } serverStates; /* func_args from wolfCrypt test.h, so don't have to pull in other stuff */ typedef struct func_args { int argc; char** argv; int return_code; } func_args; typedef struct stTCP_MESSAGE { TCP_HEADER tTCP_Header; unsigned char ucTCP_Message[MAX_TCP_LENGTH]; } TCP_MESSAGE; /* wolfSSL send callback context struct */ typedef struct stUTASKER_SENDCTX { TCP_MESSAGE* message; /* TCP frame to send */ USOCKET* socket; /* socket pointer */ unsigned int dataLen; /* length of data in message frame */ unsigned char ackd; /* has ACK been received for data (0:1) */ unsigned char flags; /* socket flags, ie: TCP_FLAG_PUSH */ } UTASKER_SENDCTX; /* wolfSSL recv callback context struct */ typedef struct stUTASKER_RECVCTX { USOCKET* socket; /* socket pointer */ unsigned int used; /* bytes used in buffer */ unsigned int offset; /* current offset in buffer, for processing */ unsigned int bufLen; /* total size of buffer in bytes */ unsigned char* buffer; /* recv data buffer */ } UTASKER_RECVCTX; /* ------------------------------- VARIABLES ------------------------------- */ static USOCKET server_socket = 0; /* server socket */ static TCP_MESSAGE stMessage; /* structure to hold TCP frame */ static UTASKER_SENDCTX sendCtx; /* wolfSSL send callback context */ static UTASKER_RECVCTX recvCtx; /* wolfSSL recv callback context */ static unsigned char ucRecvBuffer[RECV_BUFFER_LENGTH]; /* TCP recv buffer */ static serverStates serverState = serverInit; /* TLS task state */ static WOLFSSL_CTX* sslCtx; /* wolfSSL context context */ static WOLFSSL* ssl; /* wolfSSL session object */ /* server port number */ static unsigned int uiServerPort = 443; char input[80]; int wantReadTimeout = 2; /* time out after 5 consecutive WANT_READ errors */ int wantReadCounter = 0; /* ------------------------------- PROTOTYPES ------------------------------ */ int CacheRecvBuffer(UTASKER_RECVCTX* ctx, unsigned char* data, unsigned short length); int ResetRecvBuffer(UTASKER_RECVCTX* ctx); int UTasker_Receive(WOLFSSL* ssl, char* buf, int sz, void* ctx); int UTasker_Send(WOLFSSL* ssl, char* buf, int sz, void* ctx); /* ---------------------------- SOCKET LISTENERS --------------------------- */ static int fnServerListener(USOCKET Socket, unsigned char ucEvent, unsigned char *ucIp_Data, unsigned short usPortLen) { int ret = 0; switch (ucEvent) { case TCP_EVENT_CONREQ: case TCP_EVENT_CONNECTED: fnDebugMsg("status: TCP_EVENT_CONNECTED\r\n"); serverState = serverTLSNew; break; case TCP_EVENT_ACK: fnDebugMsg("status: TCP_EVENT_ACK\r\n"); /* ACK received, set ackd variable in CTX msg */ sendCtx.ackd = 1; break; case TCP_EVENT_ARP_RESOLUTION_FAILED: fnDebugMsg("status: TCP_EVENT_ARP_RESOLUTION_FAILED\r\n"); break; case TCP_EVENT_PARTIAL_ACK: fnDebugMsg("status: TCP_EVENT_PARTIAL_ACK\r\n"); break; case TCP_EVENT_REGENERATE: /* frame lost, need to resend last frame, use cached */ fnDebugMsg("status: TCP_EVENT_REGENERATE\r\n"); if (sendCtx.ackd == 0) { ret = fnSendTCP(*sendCtx.socket, (unsigned char*)&sendCtx.message->tTCP_Header, sendCtx.dataLen, sendCtx.flags); if (ret > 0) { return APP_SENT_DATA; } } break; case TCP_EVENT_DATA: /* data received from client */ fnDebugMsg("status: TCP_EVENT_DATA\r\n"); /* copy data into our temp context buffer */ if (CacheRecvBuffer(&recvCtx, ucIp_Data, usPortLen) < 0) { return APP_REJECT_DATA; } break; case TCP_EVENT_ABORT: case TCP_EVENT_CLOSE: case TCP_EVENT_CLOSED: /* server closed connection */ fnDebugMsg("status: TCP_EVENT_CLOSE || TCP_EVENT_CLOSED\r\n"); serverState = serverShutdown; break; } return APP_ACCEPT; } /* ------------------------------- APP TASK -------------------------------- */ /* * wolfSSL server app task */ extern void fnTLSServerTask(TTASKTABLE *ptrTaskTable) { int ret, errorCode, msgSz = 0; char msg[64]; /* init socket and app state */ if (serverState == serverInit) { fnDebugMsg("Starting wolfSSL Server Task\r\n"); /* run wolfCrypt tests */ ret = WolfCryptTest(); if (ret == 0) { fnDebugMsg("status: wolfCrypt Tests Passed!\r\n\r\n"); serverState = serverTLSInit; } else { fnDebugMsg("ERROR: wolfCrypt Tests Failed!\r\n\r\n"); serverState = serverIdle; } } if (serverState == serverTLSInit) { /* for debug, compile wolfSSL with DEBUG_WOLFSSL defined */ /* wolfSSL_Debugging_ON(); */ wolfSSL_Init(); /* create wolfSSL context */ sslCtx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()); if (sslCtx == NULL) { fnDebugMsg("ERROR: wolfSSL_CTX_new() failed\r\n"); serverState = serverShutdown; } else { fnDebugMsg("status: Created WOLFSSL_CTX\r\n"); } /* load server certificate */ ret = wolfSSL_CTX_use_certificate_buffer(sslCtx, server_cert_der_2048, sizeof(server_cert_der_2048), SSL_FILETYPE_ASN1); if (ret != SSL_SUCCESS) { fnDebugMsg("ERROR: wolfSSL_CTX_use_certificate_chain_buffer\r\n"); serverState = serverShutdown; } /* load server private key */ ret = wolfSSL_CTX_use_PrivateKey_buffer(sslCtx, server_key_der_2048, sizeof(server_key_der_2048), SSL_FILETYPE_ASN1); if (ret != SSL_SUCCESS) { fnDebugMsg("ERROR: wolfSSL_CTX_use_PrivateKey_buffer\r\n"); serverState = serverShutdown; } /* register wolfSSL send/recv callbacks */ wolfSSL_SetIOSend(sslCtx, UTasker_Send); wolfSSL_SetIORecv(sslCtx, UTasker_Receive); serverState = serverSocketSetup; } /* crypto tests */ if (serverState == serverSocketSetup) { /* create socket */ server_socket = fnGetTCP_Socket(TOS_MINIMISE_DELAY, TCP_DEFAULT_TIMEOUT, fnServerListener); if (server_socket >= 0) { /* set socket listening */ ret = fnTCP_Listen(server_socket, uiServerPort, 0); if (ret != server_socket) { fnDebugMsg("ERROR: fnTCP_Listen() failed\r\n"); serverState = serverIdle; } else { fnDebugMsg("status: Socket listening for connection ...\r\n"); serverState = serverListening; } } } if (serverState == serverTLSNew) { /* create wolfSSL session */ ssl = wolfSSL_new(sslCtx); if (ssl == NULL) { fnDebugMsg("ERROR: wolfSSL_new\r\n"); serverState = serverShutdown; } else { fnDebugMsg("status: Created WOLFSSL session object\r\n"); } /* set up wolfSSL send/recv context details */ sendCtx.socket = &server_socket; sendCtx.message = &stMessage; sendCtx.ackd = 0; sendCtx.dataLen = 0; sendCtx.flags = 0; recvCtx.socket = &server_socket; recvCtx.buffer = ucRecvBuffer; recvCtx.bufLen = sizeof(ucRecvBuffer); /* register wolfSSL read/write callback contexts */ wolfSSL_SetIOReadCtx(ssl, &recvCtx); wolfSSL_SetIOWriteCtx(ssl, &sendCtx); serverState = serverTLSAccept; } /* perform SSL/TLS handshake with peer */ if (serverState == serverTLSAccept) { ret = wolfSSL_accept(ssl); errorCode = wolfSSL_get_error(ssl, ret); if (ret != SSL_SUCCESS && (errorCode != SSL_ERROR_WANT_READ && errorCode != SSL_ERROR_WANT_WRITE)) { fnDebugMsg("ERROR: wolfSSL_accept: "); errorCode = wolfSSL_get_error(ssl, ret); fnDebugDec(errorCode, DISPLAY_NEGATIVE); fnDebugMsg("\r\n"); serverState = serverShutdown; } else if (ret == SSL_SUCCESS) { fnDebugMsg("wolfSSL_accept() finished\r\n"); fnDebugMsg("Client message: \r\n"); serverState = serverTLSRecv; } } /* read client message over SSL/TLS */ if (serverState == serverTLSRecv) { ret = wolfSSL_read(ssl, input, sizeof(input)-1); if (ret > 0) { input[ret] = 0; fnDebugMsg(input); fnDebugMsg("\r\n"); wantReadCounter = 0; } else if (ret < 0) { errorCode = wolfSSL_get_error(ssl, ret); if (errorCode == SSL_ERROR_WANT_READ && recvCtx.used == 0) { /* for simplicity, just time out after 5 consecutive empty read calls (adjusted using wantReadTimeout variable */ if (wantReadCounter == wantReadTimeout) serverState = serverTLSSend; else wantReadCounter++; } else if (errorCode != SSL_ERROR_WANT_READ) { fnDebugMsg("ERROR: wolfSSL_read() failed: "); errorCode = wolfSSL_get_error(ssl, ret); fnDebugDec(errorCode, DISPLAY_NEGATIVE); fnDebugMsg("\r\n"); serverState = serverShutdown; } } else { serverState = serverTLSSend; } } /* send server response */ if (serverState == serverTLSSend) { msgSz = 22; strncpy(msg, "I hear you fa shizzle!", msgSz); ret = wolfSSL_write(ssl, msg, msgSz); errorCode = wolfSSL_get_error(ssl, ret); if (errorCode != SSL_ERROR_WANT_WRITE) { if (ret != msgSz) { fnDebugMsg("ERROR: wolfSSL_write() failed: "); errorCode = wolfSSL_get_error(ssl, ret); fnDebugDec(errorCode, DISPLAY_NEGATIVE); fnDebugMsg("\r\n"); } serverState = serverShutdown; } } /* free resources and shutdown */ if (serverState == serverShutdown) { /* release socket, SSL session */ fnReleaseTCP_Socket(server_socket); wolfSSL_free(ssl); /* reset wolfSSL receive context/buffer */ ResetRecvBuffer(&recvCtx); /* reset variables and buffers */ uMemset(input, 0, sizeof(input)); wantReadCounter = 0; fnDebugMsg("status: Released Resources\r\n"); serverState = serverSocketSetup; } }