wolfssl-examples/utasker/wolfSSLServerTask.c

386 lines
11 KiB
C

/****************************************************************************
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. 2016
*****************************************************************************/
#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;
}
}