From a8e6304258ca5cea5217353c66c00090520ec88a Mon Sep 17 00:00:00 2001 From: Masaki I <32640424+tamasan238@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:07:29 +0900 Subject: [PATCH] support peer auth options --- tls-options/README.md | 62 ++++++ tls-options/client-tls-peerauth.c | 337 ++++++++++++++++++++++++++++ tls-options/server-tls-peerauth.c | 355 ++++++++++++++++++++++++++++++ 3 files changed, 754 insertions(+) create mode 100644 tls-options/client-tls-peerauth.c create mode 100644 tls-options/server-tls-peerauth.c diff --git a/tls-options/README.md b/tls-options/README.md index f811c7b8..471c4c7e 100644 --- a/tls-options/README.md +++ b/tls-options/README.md @@ -60,6 +60,68 @@ You will be able to send a message from client to server. Sending "break" as a message to the server will break the session. If you use TLS 1.3 server, You can resume many times. +### Peer Authentication + +#### Enable peer authentication + +You can choose peer authentication mode using: + +```sh +./server-tls-peerauth -a +``` + +```sh +./client-tls-peerauth -a +``` + +Peer auth mode: +- NONE (Server default) +- PEER (Client default) +- FAIL_IF_NO_PEER_CERT +- FAIL_EXCEPT_PSK + +See below for details. +https://www.wolfssl.com/documentation/manuals/wolfssl/group__Setup.html#function-wolfssl_set_verify + +If you specify the mode, myVerify() will call and display information about the certificate. + +#### Use special verify mode + +You can choose verify mode using: + +```sh +./server-tls-peerauth -m +``` + +```sh +./client-tls-peerauth -m +``` + +Verify mode: +- OVERRIDE_ERROR +- FORCE_FAIL +- USE_PREVERIFY (default) +- OVERRIDE_DATE_ERR + +If you want to use default cert files for authentication testing in server-tls-peerauth.c, please specify OVERRIDE_ERROR option. + +Because self-signed error occurs. + +#### Specify options simultaneously + +You can specify some options simultaneously. + +Example: + +```sh +./server-tls-peerauth \ + -a -m +``` + +```sh +./client-tls-peerauth \ + -a -m +``` ## Cleaning Up diff --git a/tls-options/client-tls-peerauth.c b/tls-options/client-tls-peerauth.c new file mode 100644 index 00000000..b971c4b9 --- /dev/null +++ b/tls-options/client-tls-peerauth.c @@ -0,0 +1,337 @@ +/* client-tls.c + * + * Copyright (C) 2006-2023 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 + */ + +/* the usual suspects */ +#include +#include +#include + +/* socket includes */ +#include +#include +#include +#include + +/* wolfSSL */ +#include +#include + +#define SERVER_IPV4_ADDRESS "127.0.0.1" +#define DEFAULT_PORT 11111 + +#define CA_CERT_FILE "../certs/ca-cert.pem" +#define CERT_FILE "../certs/client-cert.pem" +#define KEY_FILE "../certs/client-key.pem" + +#define CERT_BUFFER_SZ 2048 + +enum { + VERIFY_OVERRIDE_ERROR, + VERIFY_FORCE_FAIL, + VERIFY_USE_PREVERIFY, + VERIFY_DEFAULT, + VERIFY_OVERRIDE_DATE_ERR +}; + +static THREAD_LS_T int myVerifyAction = VERIFY_DEFAULT; + +static WC_INLINE int myVerify(int preverify, WOLFSSL_X509_STORE_CTX* store) +{ + char buffer[WOLFSSL_MAX_ERROR_SZ]; + WOLFSSL_X509* peer; + char issuerBuffer[CERT_BUFFER_SZ]; + char subjectBuffer[CERT_BUFFER_SZ]; + + fprintf(stderr, "In verification callback, error = %d, %s\n", store->error, + wolfSSL_ERR_error_string(store->error, buffer)); + peer = store->current_cert; + if (peer) { + wolfSSL_X509_NAME_oneline( + wolfSSL_X509_get_issuer_name(peer), issuerBuffer, CERT_BUFFER_SZ); + wolfSSL_X509_NAME_oneline( + wolfSSL_X509_get_subject_name(peer), subjectBuffer, CERT_BUFFER_SZ); + printf("\tPeer's cert info:\n issuer : %s\n subject: %s\n", + issuerBuffer, subjectBuffer); + } + else + fprintf(stderr, "\tPeer has no cert!\n"); + + printf("\tSubject's domain name at %d is %s\n", + store->error_depth, store->domain); + + switch (myVerifyAction) { + case VERIFY_OVERRIDE_ERROR: + return 1; + + case VERIFY_FORCE_FAIL: + return 0; + + case VERIFY_DEFAULT: + case VERIFY_USE_PREVERIFY: + return preverify; + + case VERIFY_OVERRIDE_DATE_ERR: + if (store->error == ASN_BEFORE_DATE_E + || store->error == ASN_AFTER_DATE_E) + return 1; + return 0; + } + fprintf(stderr, "Invalid verify action.\n"); + exit(1); +} + +int switchPeerAuthMode(char *mode) +{ + if (XSTRCMP("NONE", mode) == 0) { + return SSL_VERIFY_NONE; + } + else if (XSTRCMP("PEER", mode) == 0) { + return SSL_VERIFY_PEER; + } + else if (XSTRCMP("FAIL_IN_NO_PEER_CERT", mode) == 0) { + return SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + else if (XSTRCMP("FAIL_EXCEPT_PSK", mode) == 0) { + return SSL_VERIFY_FAIL_EXCEPT_PSK; + } + fprintf(stderr, "Invalid peer auth mode.\n"); + exit(1); +} + +int switchMyVerifyAction(char *mode) +{ + if (XSTRCMP("OVERRIDE_ERROR", mode) == 0) { + return VERIFY_OVERRIDE_ERROR; + } + else if (XSTRCMP("FORCE_FAIL", mode) == 0) { + return VERIFY_FORCE_FAIL; + } + else if (XSTRCMP("USE_PREVERIFY", mode) == 0) { + return VERIFY_USE_PREVERIFY; + } + else if (XSTRCMP("OVERRIDE_DATE_ERR", mode) == 0) { + return VERIFY_OVERRIDE_DATE_ERR; + } + fprintf(stderr, "Invalid verify action.\n"); + exit(1); +} + +int main(int argc, char** argv) +{ + int sockfd = SOCKET_INVALID; + struct sockaddr_in servAddr; + char buff[256]; + size_t len; + int ret; + int diff = 0; + int peerAuthMode = WOLFSSL_VERIFY_DEFAULT; + + /* declare wolfSSL objects */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* Check options */ + if (argc >= 3) { + if (XSTRCMP("-a", argv[1]) == 0) { + peerAuthMode = switchPeerAuthMode(argv[2]); + diff += 2; + } + if (XSTRCMP("-m", argv[1]) == 0) { + myVerifyAction = switchMyVerifyAction(argv[2]); + diff += 2; + } + } + if (argc >= 5) { + if (XSTRCMP("-a", argv[3]) == 0) { + peerAuthMode = switchPeerAuthMode(argv[4]); + diff += 2; + } + if (XSTRCMP("-m", argv[3]) == 0) { + myVerifyAction = switchMyVerifyAction(argv[4]); + diff += 2; + } + } + + /* Set specify cert/key files */ + if (argc-diff != 1) { + printf("usage:\n" + "\t./client-tls-peerauth -a \n" + "\t./client-tls-peerauth -m \n" + "\t./client-tls-peerauth \\\n" + "\t\t-a -m \n" + "\n" + "Peer auth mode:\n" + "\tNONE, PEER,\n" + "\tFAIL_IF_NO_PEER_CERT,\n" + "\tFAIL_EXCEPT_PSK\n" + "\n" + "Verify mode:\n" + "\tOVERRIDE_ERROR,\n" + "\tFORCE_FAIL,\n" + "\tUSE_PREVERIFY,\n" + "\tOVERRIDE_DATE_ERR\n"); + 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 define */ + if (inet_pton(AF_INET, SERVER_IPV4_ADDRESS, &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 wolfSSL initialization and configuration */ + /*---------------------------------*/ + /* Initialize wolfSSL */ + if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: Failed to initialize the library\n"); + goto exit; + } + + /* Create and initialize WOLFSSL_CTX */ + if ((ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())) == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n"); + ret = -1; + goto exit; + } + + /* If peer auth is enabled, Load CA certificates into WOLFSSL_CTX */ + if (peerAuthMode != WOLFSSL_VERIFY_NONE) { + if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL)) + != SSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, " + "please check the file.\n", CA_CERT_FILE); + goto exit; + } + } + + /* Set peer auth mode */ + if (peerAuthMode != WOLFSSL_VERIFY_DEFAULT) { + wolfSSL_CTX_set_verify(ctx, peerAuthMode, myVerify); + } + + /* Load client 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 client 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; + } + + /* 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; + } + + /* Connect to wolfSSL on the server side */ + if ((ret = wolfSSL_connect(ssl)) != SSL_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); + + /* Bidirectional shutdown */ + while (wolfSSL_shutdown(ssl) == SSL_SHUTDOWN_NOT_DONE) { + printf("Shutdown not complete\n"); + } + + printf("Shutdown complete\n"); + + ret = 0; + +exit: + /* Cleanup and return */ + if (ssl) + wolfSSL_free(ssl); /* Free the wolfSSL object */ + if (sockfd != SOCKET_INVALID) + close(sockfd); /* Close the connection to the server */ + if (ctx) + wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */ + wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */ + + return ret; /* Return reporting a success */ +} diff --git a/tls-options/server-tls-peerauth.c b/tls-options/server-tls-peerauth.c new file mode 100644 index 00000000..bb8e8e33 --- /dev/null +++ b/tls-options/server-tls-peerauth.c @@ -0,0 +1,355 @@ +/* server-tls.c + * + * Copyright (C) 2006-2023 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 + */ + +/* the usual suspects */ +#include +#include +#include + +/* socket includes */ +#include +#include +#include +#include + +/* wolfSSL */ +#include +#include + +#define DEFAULT_PORT 11111 + +#define CA_CERT_FILE "../certs/ca-cert.pem" +#define CERT_FILE "../certs/server-cert.pem" +#define KEY_FILE "../certs/server-key.pem" + +#define CERT_BUFFER_SZ 2048 + +enum { + VERIFY_OVERRIDE_ERROR, + VERIFY_FORCE_FAIL, + VERIFY_USE_PREVERIFY, + VERIFY_DEFAULT, + VERIFY_OVERRIDE_DATE_ERR +}; + +static THREAD_LS_T int myVerifyAction = VERIFY_DEFAULT; + +static WC_INLINE int myVerify(int preverify, WOLFSSL_X509_STORE_CTX* store) +{ + char buffer[WOLFSSL_MAX_ERROR_SZ]; + WOLFSSL_X509* peer; + char issuerBuffer[CERT_BUFFER_SZ]; + char subjectBuffer[CERT_BUFFER_SZ]; + + fprintf(stderr, "In verification callback, error = %d, %s\n", store->error, + wolfSSL_ERR_error_string(store->error, buffer)); + peer = store->current_cert; + if (peer) { + wolfSSL_X509_NAME_oneline( + wolfSSL_X509_get_issuer_name(peer), issuerBuffer, CERT_BUFFER_SZ); + wolfSSL_X509_NAME_oneline( + wolfSSL_X509_get_subject_name(peer), subjectBuffer, CERT_BUFFER_SZ); + printf("\tPeer's cert info:\n issuer : %s\n subject: %s\n", + issuerBuffer, subjectBuffer); + } + else + fprintf(stderr, "\tPeer has no cert!\n"); + + printf("\tSubject's domain name at %d is %s\n", + store->error_depth, store->domain); + + switch (myVerifyAction) { + case VERIFY_OVERRIDE_ERROR: + return 1; + + case VERIFY_FORCE_FAIL: + return 0; + + case VERIFY_DEFAULT: + case VERIFY_USE_PREVERIFY: + return preverify; + + case VERIFY_OVERRIDE_DATE_ERR: + if (store->error == ASN_BEFORE_DATE_E + || store->error == ASN_AFTER_DATE_E) + return 1; + return 0; + } + fprintf(stderr, "Invalid verify action.\n"); + exit(1); +} + +int switchPeerAuthMode(char *mode) +{ + if (XSTRCMP("NONE", mode) == 0) { + return SSL_VERIFY_NONE; + } + else if (XSTRCMP("PEER", mode) == 0) { + return SSL_VERIFY_PEER; + } + else if (XSTRCMP("FAIL_IN_NO_PEER_CERT", mode) == 0) { + return SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + else if (XSTRCMP("FAIL_EXCEPT_PSK", mode) == 0) { + return SSL_VERIFY_FAIL_EXCEPT_PSK; + } + fprintf(stderr, "Invalid peer auth mode.\n"); + exit(1); +} + +int switchMyVerifyAction(char *mode) +{ + if (XSTRCMP("OVERRIDE_ERROR", mode) == 0) { + return VERIFY_OVERRIDE_ERROR; + } + else if (XSTRCMP("FORCE_FAIL", mode) == 0) { + return VERIFY_FORCE_FAIL; + } + else if (XSTRCMP("USE_PREVERIFY", mode) == 0) { + return VERIFY_USE_PREVERIFY; + } + else if (XSTRCMP("OVERRIDE_DATE_ERR", mode) == 0) { + return VERIFY_OVERRIDE_DATE_ERR; + } + fprintf(stderr, "Invalid verify action.\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + 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; + int ret; + int diff = 0; + int peerAuthMode = WOLFSSL_VERIFY_DEFAULT; + const char* reply = "I hear ya fa shizzle!\n"; + + /* declare wolfSSL objects */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* Initialize wolfSSL */ + wolfSSL_Init(); + + /* Check options */ + if (argc >= 3) { + if (XSTRCMP("-a", argv[1]) == 0) { + peerAuthMode = switchPeerAuthMode(argv[2]); + diff += 2; + } + if (XSTRCMP("-m", argv[1]) == 0) { + myVerifyAction = switchMyVerifyAction(argv[2]); + diff += 2; + } + } + if (argc >= 5) { + if (XSTRCMP("-a", argv[3]) == 0) { + peerAuthMode = switchPeerAuthMode(argv[4]); + diff += 2; + } + if (XSTRCMP("-m", argv[3]) == 0) { + myVerifyAction = switchMyVerifyAction(argv[4]); + diff += 2; + } + } + + /* Set specify cert/key files */ + if (argc-diff != 1) { + printf("usage:\n" + "\t./server-tls-peerauth -a \n" + "\t./server-tls-peerauth -m \n" + "\t./server-tls-peerauth \\\n" + "\t\t-a -m \n" + "\n" + "Peer auth mode:\n" + "\tNONE, PEER,\n" + "\tFAIL_IF_NO_PEER_CERT,\n" + "\tFAIL_EXCEPT_PSK\n" + "\n" + "Verify mode:\n" + "\tOVERRIDE_ERROR,\n" + "\tFORCE_FAIL,\n" + "\tUSE_PREVERIFY,\n" + "\tOVERRIDE_DATE_ERR\n"); + 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; + } + + /* Create and initialize WOLFSSL_CTX */ + if ((ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method())) == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n"); + ret = -1; + goto exit; + } + + /* Set peer auth mode */ + if (peerAuthMode != WOLFSSL_VERIFY_DEFAULT) { + wolfSSL_CTX_set_verify(ctx, peerAuthMode, myVerify); + } + + /* If peer auth is enabled, Load CA certificates into WOLFSSL_CTX */ + if (peerAuthMode != WOLFSSL_VERIFY_DEFAULT + && peerAuthMode != WOLFSSL_VERIFY_NONE) { + if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL)) + != SSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, " + "please check the file.\n", CA_CERT_FILE); + 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; + } + + /* 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 */ + + /* 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; + } + + /* 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); + + /* Establish TLS connection */ + ret = wolfSSL_accept(ssl); + if (ret != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_accept error = %d\n", + wolfSSL_get_error(ssl, ret)); + 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 */ + ssl = NULL; + close(connd); /* Close the connection to the client */ + } + + ret = 0; + +exit: + /* Cleanup and return */ + if (ssl) + wolfSSL_free(ssl); /* Free the wolfSSL object */ + if (connd != SOCKET_INVALID) + close(connd); /* Close the connection to the client */ + if (sockfd != SOCKET_INVALID) + close(sockfd); /* Close the socket listening for clients */ + if (ctx) + wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */ + wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */ + + return ret; /* Return reporting a success */ +}