diff --git a/.gitignore b/.gitignore index bc512404..d34fbf37 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,8 @@ android/wolfssljni-ndk-sample/proguard-project.txt /tls/server-tls-threaded /tls/client-tls-pkcs12 /tls/client-tls-cryptocb +/tls/server-tls-pkcallback +/tls/client-tls-pkcallback tls/client-tls-uart tls/server-tls-uart diff --git a/tls/README.md b/tls/README.md index 42a4ee35..96d2aafb 100644 --- a/tls/README.md +++ b/tls/README.md @@ -1242,3 +1242,52 @@ Sending test string Sent (0): Testing 1, 2 and 3 Read (0): Testing 1, 2 and 3 ``` + + +## TLS Example with PK Callbacks and optionally Async + +See `server-tls-pkcallback.c` and `client-tls-pkcallback.c`. + +The top of both files have an optional build setting to gate use of ECC/RSA and TLS v1.2 or TLS v1.3: + +``` +#define USE_ECDHE_ECDSA +#define USE_TLSV13 +``` + +For this example it uses the `--enable-pkcallbacks` or `HAVE_PK_CALLBACKS` feature. +Optionally if using the `--enable-asynccrypt` option and wolfSSL Async code this also shows being able to return `WC_PENDING_E` while the asymmetric key operation is ocurring. + +``` +./configure --enable-pkcallbacks [--enable-asynccrypt] +make +sudo make install +``` + +Example Output: + +``` +./server-tls-pkcallback +Waiting for a connection... +PK ECC Sign: inSz 32, keySz 121 +PK ECC Sign: Async Simulate +PK ECC Sign: inSz 32, keySz 121 +PK ECC Sign: Curve ID 7 +PK ECC Sign: ret 0 outSz 72 +Client connected successfully +Client: test + +Shutdown complete +Waiting for a connection... +``` + +``` +% ./client-tls-pkcallback 127.0.0.1 +PK ECC Sign: inSz 32, keySz 121 +PK ECC Sign: Async Simulate +PK ECC Sign: inSz 32, keySz 121 +PK ECC Sign: Curve ID 7 +PK ECC Sign: ret 0 outSz 71 +Message for server: test +Server: I hear ya fa shizzle! +``` diff --git a/tls/client-tls-pkcallback.c b/tls/client-tls-pkcallback.c new file mode 100644 index 00000000..fd978ea9 --- /dev/null +++ b/tls/client-tls-pkcallback.c @@ -0,0 +1,367 @@ +/* client-tls-pkcallback.c + * + * Copyright (C) 2006-2022 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 + */ + +/* This example shows how to register a private key callback and optionally + * use the asynchronous version of the code to return a WC_PENDING_E while the + * hardware is processing */ + +#include +#include +#include +#include +#include +#include +#include + +/* wolfSSL */ +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include +#include +#include +#include +#include + +#define DEFAULT_PORT 11111 + +#define USE_ECDHE_ECDSA +#define USE_TLSV13 + +#ifdef USE_ECDHE_ECDSA +#define CERT_FILE "../certs/client-ecc-cert.pem" +#define KEY_FILE "../certs/ecc-client-key.pem" +#define CA_FILE "../certs/ca-ecc-cert.pem" +#else +#define CERT_FILE "../certs/client-cert.pem" +#define KEY_FILE "../certs/client-key.pem" +#define CA_FILE "../certs/ca-cert.pem" +#endif + +typedef struct { + const char* keyFile; + ecc_key key; + int state; +} PkCbInfo; + +#ifdef HAVE_PK_CALLBACKS +/* reads file size, allocates buffer, reads into buffer, returns buffer */ +static int load_file(const char* fname, byte** buf, size_t* bufLen) +{ + int ret; + long int fileSz; + XFILE lFile; + + if (fname == NULL || buf == NULL || bufLen == NULL) + return BAD_FUNC_ARG; + + /* set defaults */ + *buf = NULL; + *bufLen = 0; + + /* open file (read-only binary) */ + lFile = XFOPEN(fname, "rb"); + if (!lFile) { + printf("Error loading %s\n", fname); + return BAD_PATH_ERROR; + } + + fseek(lFile, 0, SEEK_END); + fileSz = (int)ftell(lFile); + rewind(lFile); + if (fileSz > 0) { + *bufLen = (size_t)fileSz; + *buf = (byte*)malloc(*bufLen); + if (*buf == NULL) { + ret = MEMORY_E; + printf("Error allocating %lu bytes\n", (unsigned long)*bufLen); + } + else { + size_t readLen = fread(*buf, *bufLen, 1, lFile); + + /* check response code */ + ret = (readLen > 0) ? 0 : -1; + } + } + else { + ret = BUFFER_E; + } + fclose(lFile); + + return ret; +} + +static int load_key_file(const char* fname, byte** derBuf, word32* derLen) +{ + int ret; + byte* buf = NULL; + size_t bufLen; + + ret = load_file(fname, &buf, &bufLen); + if (ret != 0) + return ret; + + *derBuf = (byte*)malloc(bufLen); + if (*derBuf == NULL) { + free(buf); + return MEMORY_E; + } + + ret = wc_KeyPemToDer(buf, (word32)bufLen, *derBuf, (word32)bufLen, NULL); + if (ret < 0) { + free(buf); + free(*derBuf); + return ret; + } + *derLen = ret; + free(buf); + + return 0; +} + +static int myEccSign(WOLFSSL* ssl, const byte* in, word32 inSz, + byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx) +{ + int ret; + byte* keyBuf = (byte*)key; + PkCbInfo* cbInfo = (PkCbInfo*)ctx; + + printf("PK ECC Sign: inSz %u, keySz %u\n", inSz, keySz); + +#ifdef WOLFSSL_ASYNC_CRYPT + if (cbInfo->state == 0) { + cbInfo->state++; + printf("PK ECC Sign: Async Simulate\n"); + return WC_PENDING_E; + } +#endif + + ret = load_key_file(cbInfo->keyFile, &keyBuf, &keySz); + if (ret == 0) { + ret = wc_ecc_init(&cbInfo->key); + if (ret == 0) { + word32 idx = 0; + ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &cbInfo->key, keySz); + if (ret == 0) { + WC_RNG *rng = wolfSSL_GetRNG(ssl); + + printf("PK ECC Sign: Curve ID %d\n", cbInfo->key.dp->id); + ret = wc_ecc_sign_hash(in, inSz, out, outSz, rng, &cbInfo->key); + } + wc_ecc_free(&cbInfo->key); + } + } + free(keyBuf); + +#ifdef WOLFSSL_ASYNC_CRYPT + cbInfo->state = 0; +#endif + + printf("PK ECC Sign: ret %d outSz %u\n", ret, *outSz); + + return ret; +} +#endif /* HAVE_PK_CALLBACKS */ + +int main(int argc, char** argv) +{ + int ret = 0, err; + int sockfd = SOCKET_INVALID; + struct sockaddr_in servAddr; + char buff[256]; + size_t len; + + /* declare wolfSSL objects */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* PK callback context */ + PkCbInfo myCtx; + memset(&myCtx, 0, sizeof(myCtx)); + myCtx.keyFile = KEY_FILE; + + /* Check for proper calling convention */ + if (argc != 2) { + printf("usage: %s \n", argv[0]); + return 0; + } + + /* Create a socket that uses an internet IPv4 address, + * Sets the socket to be stream based (TCP), + * 0 means choose the default protocol. */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "ERROR: failed to create the socket\n"); + ret = -1; + goto exit; + } + + /* Initialize the server address struct with zeros */ + memset(&servAddr, 0, sizeof(servAddr)); + + /* Fill in the server address */ + servAddr.sin_family = AF_INET; /* using IPv4 */ + servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ + + /* Get the server IPv4 address from the command line call */ + if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) { + fprintf(stderr, "ERROR: invalid address\n"); + ret = -1; + goto exit; + } + + /* Connect to the server */ + if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr))) + == -1) { + fprintf(stderr, "ERROR: failed to connect\n"); + goto exit; + } + + /*---------------------------------*/ + /* Start of security */ + /*---------------------------------*/ +#if 0 + wolfSSL_Debugging_ON(); +#endif + + /* Initialize wolfSSL */ + if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: Failed to initialize the library\n"); + goto exit; + } + + /* Create and initialize WOLFSSL_CTX */ +#ifdef USE_TLSV13 + ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); +#else + ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()); +#endif + if (ctx == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n"); + ret = -1; + goto exit; + } + +#ifdef HAVE_PK_CALLBACKS + /* register an ECC sign callback for the long term key */ + wolfSSL_CTX_SetEccSignCb(ctx, myEccSign); +#else + printf("Warning: PK not compiled in! Please configure wolfSSL with " + " --enable-pkcallbacks and try again\n"); +#endif + + /* Mutual Authentication */ + /* Load client certificate into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, WOLFSSL_FILETYPE_PEM)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + CERT_FILE); + goto exit; + } + + /* Load client key into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, WOLFSSL_FILETYPE_PEM)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + KEY_FILE); + goto exit; + } + + /* Load CA certificate into WOLFSSL_CTX for validating peer */ + if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CA_FILE, NULL)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + CA_FILE); + goto exit; + } + + /* validate peer certificate */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL); + + /* Create a WOLFSSL object */ + if ((ssl = wolfSSL_new(ctx)) == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL object\n"); + ret = -1; + goto exit; + } + + /* Attach wolfSSL to the socket */ + if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: Failed to set the file descriptor\n"); + goto exit; + } + +#ifdef HAVE_PK_CALLBACKS + /* setup the PK context */ + wolfSSL_SetEccSignCtx(ssl, &myCtx); +#endif + + /* Connect to wolfSSL on the server side */ + do { + ret = wolfSSL_connect(ssl); + err = wolfSSL_get_error(ssl, ret); + } while (err == WC_PENDING_E); + if (ret != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to connect to wolfSSL\n"); + goto exit; + } + + /* Get a message for the server from stdin */ + printf("Message for server: "); + memset(buff, 0, sizeof(buff)); + if (fgets(buff, sizeof(buff), stdin) == NULL) { + fprintf(stderr, "ERROR: failed to get message for server\n"); + ret = -1; + goto exit; + } + len = strnlen(buff, sizeof(buff)); + + /* Send the message to the server */ + if ((ret = wolfSSL_write(ssl, buff, len)) != len) { + fprintf(stderr, "ERROR: failed to write entire message\n"); + fprintf(stderr, "%d bytes of %d bytes were sent", ret, (int) len); + goto exit; + } + + /* Read the server data into our buff array */ + memset(buff, 0, sizeof(buff)); + if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) { + fprintf(stderr, "ERROR: failed to read\n"); + goto exit; + } + + /* Print to stdout any data the server sends */ + printf("Server: %s\n", buff); + + ret = 0; /* success */ + +exit: + /* Cleanup and return */ + if (sockfd != SOCKET_INVALID) + close(sockfd); + if (ssl != NULL) + wolfSSL_free(ssl); + if (ctx != NULL) + wolfSSL_CTX_free(ctx); + + wolfSSL_Cleanup(); + + return ret; +} diff --git a/tls/server-tls-pkcallback.c b/tls/server-tls-pkcallback.c new file mode 100644 index 00000000..c42650fe --- /dev/null +++ b/tls/server-tls-pkcallback.c @@ -0,0 +1,402 @@ +/* server-tls-pkcallback.c + * + * Copyright (C) 2006-2022 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 + */ + +/* This example shows how to register a private key callback and optionally + * use the asynchronous version of the code to return a WC_PENDING_E while the + * hardware is processing */ + +#include +#include +#include +#include +#include +#include +#include + +/* wolfSSL */ +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include +#include +#include +#include +#include + +#define DEFAULT_PORT 11111 + +#define USE_ECDHE_ECDSA +#define USE_TLSV13 + +#ifdef USE_ECDHE_ECDSA +#define CERT_FILE "../certs/server-ecc.pem" +#define KEY_FILE "../certs/ecc-key.pem" +#define CA_FILE "../certs/client-ecc-cert.pem" +#else +#define CERT_FILE "../certs/server-cert.pem" +#define KEY_FILE "../certs/server-key.pem" +#define CA_FILE "../certs/client-cert.pem" +#endif + +typedef struct { + const char* keyFile; + ecc_key key; + int state; +} PkCbInfo; + +#ifdef HAVE_PK_CALLBACKS +/* reads file size, allocates buffer, reads into buffer, returns buffer */ +static int load_file(const char* fname, byte** buf, size_t* bufLen) +{ + int ret; + long int fileSz; + XFILE lFile; + + if (fname == NULL || buf == NULL || bufLen == NULL) + return BAD_FUNC_ARG; + + /* set defaults */ + *buf = NULL; + *bufLen = 0; + + /* open file (read-only binary) */ + lFile = XFOPEN(fname, "rb"); + if (!lFile) { + printf("Error loading %s\n", fname); + return BAD_PATH_ERROR; + } + + fseek(lFile, 0, SEEK_END); + fileSz = (int)ftell(lFile); + rewind(lFile); + if (fileSz > 0) { + *bufLen = (size_t)fileSz; + *buf = (byte*)malloc(*bufLen); + if (*buf == NULL) { + ret = MEMORY_E; + printf("Error allocating %lu bytes\n", (unsigned long)*bufLen); + } + else { + size_t readLen = fread(*buf, *bufLen, 1, lFile); + + /* check response code */ + ret = (readLen > 0) ? 0 : -1; + } + } + else { + ret = BUFFER_E; + } + fclose(lFile); + + return ret; +} + +static int load_key_file(const char* fname, byte** derBuf, word32* derLen) +{ + int ret; + byte* buf = NULL; + size_t bufLen; + + ret = load_file(fname, &buf, &bufLen); + if (ret != 0) + return ret; + + *derBuf = (byte*)malloc(bufLen); + if (*derBuf == NULL) { + free(buf); + return MEMORY_E; + } + + ret = wc_KeyPemToDer(buf, (word32)bufLen, *derBuf, (word32)bufLen, NULL); + if (ret < 0) { + free(buf); + free(*derBuf); + return ret; + } + *derLen = ret; + free(buf); + + return 0; +} + +static int myEccSign(WOLFSSL* ssl, const byte* in, word32 inSz, + byte* out, word32* outSz, const byte* key, word32 keySz, void* ctx) +{ + int ret; + byte* keyBuf = (byte*)key; + PkCbInfo* cbInfo = (PkCbInfo*)ctx; + + printf("PK ECC Sign: inSz %u, keySz %u\n", inSz, keySz); + +#ifdef WOLFSSL_ASYNC_CRYPT + if (cbInfo->state == 0) { + cbInfo->state++; + printf("PK ECC Sign: Async Simulate\n"); + return WC_PENDING_E; + } +#endif + + ret = load_key_file(cbInfo->keyFile, &keyBuf, &keySz); + if (ret == 0) { + ret = wc_ecc_init(&cbInfo->key); + if (ret == 0) { + word32 idx = 0; + ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &cbInfo->key, keySz); + if (ret == 0) { + WC_RNG *rng = wolfSSL_GetRNG(ssl); + + printf("PK ECC Sign: Curve ID %d\n", cbInfo->key.dp->id); + ret = wc_ecc_sign_hash(in, inSz, out, outSz, rng, &cbInfo->key); + } + wc_ecc_free(&cbInfo->key); + } + } + free(keyBuf); +#ifdef WOLFSSL_ASYNC_CRYPT + cbInfo->state = 0; +#endif + + printf("PK ECC Sign: ret %d outSz %u\n", ret, *outSz); + + return ret; +} +#endif /* HAVE_PK_CALLBACKS */ + +int main(int argc, char** argv) +{ + int ret, err; + int sockfd = SOCKET_INVALID; + int connd = SOCKET_INVALID; + struct sockaddr_in servAddr; + struct sockaddr_in clientAddr; + socklen_t size = sizeof(clientAddr); + char buff[256]; + size_t len; + int shutdown = 0; + const char* reply = "I hear ya fa shizzle!\n"; + int on; + + /* PK callback context */ + PkCbInfo myCtx; + memset(&myCtx, 0, sizeof(myCtx)); + myCtx.keyFile = KEY_FILE; + + /* declare wolfSSL objects */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* Initialize the server address struct with zeros */ + memset(&servAddr, 0, sizeof(servAddr)); + + /* Fill in the server address */ + servAddr.sin_family = AF_INET; /* using IPv4 */ + servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ + servAddr.sin_addr.s_addr = INADDR_ANY; /* from anywhere */ + + /* Create a socket that uses an internet IPv4 address, + * Sets the socket to be stream based (TCP), + * 0 means choose the default protocol. */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "ERROR: failed to create the socket\n"); + ret = -1; + goto exit; + } + + /* make sure server is setup for reuse addr/port */ + on = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (char*)&on, (socklen_t)sizeof(on)); +#ifdef SO_REUSEPORT + setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, + (char*)&on, (socklen_t)sizeof(on)); +#endif + + + /* Bind the server socket to our port */ + if (bind(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) { + fprintf(stderr, "ERROR: failed to bind\n"); + ret = -1; + goto exit; + } + + /* Listen for a new connection, allow 5 pending connections */ + if (listen(sockfd, 5) == -1) { + fprintf(stderr, "ERROR: failed to listen\n"); + ret = -1; + goto exit; + } + + + + /*---------------------------------*/ + /* Start of security */ + /*---------------------------------*/ +#if 0 + wolfSSL_Debugging_ON(); +#endif + + /* Initialize wolfSSL */ + wolfSSL_Init(); + + /* Create and initialize WOLFSSL_CTX */ +#ifdef USE_TLSV13 + ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); +#else + ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()); +#endif + if (ctx == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n"); + ret = -1; + goto exit; + } + + /* Load server certificates into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + CERT_FILE); + goto exit; + } + + /* Load server key into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + KEY_FILE); + goto exit; + } + + /* Load CA certificate into WOLFSSL_CTX for validating peer */ + if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CA_FILE, NULL)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + CA_FILE); + goto exit; + } + + /* enable mutual authentication */ + wolfSSL_CTX_set_verify(ctx, + WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + +#ifdef HAVE_PK_CALLBACKS + /* register an ECC sign callback for the long term key */ + wolfSSL_CTX_SetEccSignCb(ctx, myEccSign); +#else + printf("Warning: PK not compiled in! Please configure wolfSSL with " + " --enable-pkcallbacks and try again\n"); +#endif + + + /* Continue to accept clients until shutdown is issued */ + while (!shutdown) { + printf("Waiting for a connection...\n"); + + /* Accept client connections */ + if ((connd = accept(sockfd, (struct sockaddr*)&clientAddr, &size)) + == -1) { + fprintf(stderr, "ERROR: failed to accept the connection\n\n"); + ret = -1; + goto exit; + } + + /* Create a WOLFSSL object */ + if ((ssl = wolfSSL_new(ctx)) == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL object\n"); + ret = -1; + goto exit; + } + + /* Attach wolfSSL to the socket */ + wolfSSL_set_fd(ssl, connd); + + #ifdef HAVE_PK_CALLBACKS + /* setup the PK context */ + wolfSSL_SetEccSignCtx(ssl, &myCtx); + #endif + + /* Establish TLS connection */ + do { + ret = wolfSSL_accept(ssl); + err = wolfSSL_get_error(ssl, ret); + } while (err == WC_PENDING_E); + if (ret != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_accept error = %d\n", err); + goto exit; + } + + printf("Client connected successfully\n"); + + + /* Read the client data into our buff array */ + memset(buff, 0, sizeof(buff)); + if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) { + fprintf(stderr, "ERROR: failed to read\n"); + goto exit; + } + + /* Print to stdout any data the client sends */ + printf("Client: %s\n", buff); + + /* Check for server shutdown command */ + if (strncmp(buff, "shutdown", 8) == 0) { + printf("Shutdown command issued!\n"); + shutdown = 1; + } + + + /* Write our reply into buff */ + memset(buff, 0, sizeof(buff)); + memcpy(buff, reply, strlen(reply)); + len = strnlen(buff, sizeof(buff)); + + /* Reply back to the client */ + if ((ret = wolfSSL_write(ssl, buff, len)) != len) { + fprintf(stderr, "ERROR: failed to write\n"); + goto exit; + } + + /* Notify the client that the connection is ending */ + wolfSSL_shutdown(ssl); + printf("Shutdown complete\n"); + + /* Cleanup after this connection */ + wolfSSL_free(ssl); /* Free the wolfSSL object */ + close(connd); /* Close the connection to the client */ + connd = SOCKET_INVALID; + } + + ret = 0; /* success */ + +exit: + + /* Cleanup and return */ + if (ssl != NULL) + wolfSSL_free(ssl); + if (connd != SOCKET_INVALID) + close(connd); + if (sockfd != SOCKET_INVALID) + close(sockfd); + if (ctx != NULL) + wolfSSL_CTX_free(ctx); + wolfSSL_Cleanup(); + + return ret; +}