Files
wolfssl/examples/server/server.c
Sean Parkinson 5bddb2e4ef Changes for Nginx
Support TLS v1.3 clients connecting to Nginx.
Fix for PSS to not advertise hash unless the signature fits the private
key size.
Allow curves to be chosen by user.
Support maximum verification depth (maximum number of untrusted certs in
chain.)
Add support for SSL_is_server() API.
Fix number of certificates in chain when using
wolfSSL_CTX_add_extra_chain_cert().
Allow TLS v1.2 client hello parsing to call TLS v1.3 parsing when
SupportedVersions extension seen.
Minor fixes.
2017-07-04 09:37:44 +10:00

1548 lines
47 KiB
C

/* server.c
*
* Copyright (C) 2006-2017 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* 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-1335, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cyassl/ssl.h> /* name change portability layer */
#include <cyassl/ctaocrypt/settings.h>
#ifdef HAVE_ECC
#include <cyassl/ctaocrypt/ecc.h> /* ecc_fp_free */
#endif
#if defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET)
#include <stdio.h>
#include <string.h>
#if !defined(WOLFSSL_MDK_ARM)
#include "cmsis_os.h"
#include "rl_fs.h"
#include "rl_net.h"
#else
#include "rtl.h"
#include "wolfssl_MDK_ARM.h"
#endif
#endif
#include <cyassl/openssl/ssl.h>
#include <cyassl/test.h>
#include "examples/server/server.h"
#ifndef NO_WOLFSSL_SERVER
#ifdef WOLFSSL_ASYNC_CRYPT
static int devId = INVALID_DEVID;
#endif
/* Note on using port 0: if the server uses port 0 to bind an ephemeral port
* number and is using the ready file for scripted testing, the code in
* test.h will write the actual port number into the ready file for use
* by the client. */
static const char webServerMsg[] =
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
"Connection: close\n"
"\n"
"<html>\n"
"<head>\n"
"<title>Welcome to wolfSSL!</title>\n"
"</head>\n"
"<body>\n"
"<p>wolfSSL has successfully performed handshake!</p>\n"
"</body>\n"
"</html>\n";
int runWithErrors = 0; /* Used with -x flag to run err_sys vs. print errors */
#ifdef CYASSL_CALLBACKS
Timeval srvTo;
static int srvHandShakeCB(HandShakeInfo* info)
{
(void)info;
return 0;
}
static int srvTimeoutCB(TimeoutInfo* info)
{
(void)info;
return 0;
}
#endif
#ifndef NO_HANDSHAKE_DONE_CB
static int myHsDoneCb(WOLFSSL* ssl, void* user_ctx)
{
(void)user_ctx;
(void)ssl;
/* printf("Notified HandShake done\n"); */
/* return negative number to end TLS connection now */
return 0;
}
#endif
static void err_sys_ex(int out, const char* msg)
{
if (out == 1) { /* if server is running w/ -x flag, print error w/o exit */
printf("wolfSSL error: %s\n", msg);
printf("Continuing server execution...\n\n");
} else {
err_sys(msg);
}
}
static int NonBlockingSSL_Accept(SSL* ssl)
{
#ifndef CYASSL_CALLBACKS
int ret = SSL_accept(ssl);
#else
int ret = CyaSSL_accept_ex(ssl, srvHandShakeCB, srvTimeoutCB, srvTo);
#endif
int error = SSL_get_error(ssl, 0);
SOCKET_T sockfd = (SOCKET_T)CyaSSL_get_fd(ssl);
int select_ret = 0;
while (ret != SSL_SUCCESS && (error == SSL_ERROR_WANT_READ ||
error == SSL_ERROR_WANT_WRITE ||
error == WC_PENDING_E)) {
int currTimeout = 1;
if (error == SSL_ERROR_WANT_READ) {
/* printf("... server would read block\n"); */
}
else if (error == SSL_ERROR_WANT_WRITE) {
/* printf("... server would write block\n"); */
}
#ifdef WOLFSSL_ASYNC_CRYPT
else if (error == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
if (error != WC_PENDING_E) {
#ifdef CYASSL_DTLS
currTimeout = CyaSSL_dtls_get_current_timeout(ssl);
#endif
select_ret = tcp_select(sockfd, currTimeout);
}
if ((select_ret == TEST_RECV_READY) ||
(select_ret == TEST_ERROR_READY) || error == WC_PENDING_E) {
#ifndef CYASSL_CALLBACKS
ret = SSL_accept(ssl);
#else
ret = CyaSSL_accept_ex(ssl,
srvHandShakeCB, srvTimeoutCB, srvTo);
#endif
error = SSL_get_error(ssl, 0);
}
else if (select_ret == TEST_TIMEOUT && !CyaSSL_dtls(ssl)) {
error = SSL_ERROR_WANT_READ;
}
#ifdef CYASSL_DTLS
else if (select_ret == TEST_TIMEOUT && CyaSSL_dtls(ssl) &&
CyaSSL_dtls_got_timeout(ssl) >= 0) {
error = SSL_ERROR_WANT_READ;
}
#endif
else {
error = SSL_FATAL_ERROR;
}
}
return ret;
}
/* Echo number of bytes specified by -e arg */
int ServerEchoData(SSL* ssl, int clientfd, int echoData, int throughput)
{
int ret = 0, err;
double start = 0, rx_time = 0, tx_time = 0;
int xfer_bytes = 0, select_ret, len, rx_pos;
char* buffer;
buffer = (char*)malloc(TEST_BUFFER_SIZE);
if (!buffer) {
err_sys_ex(runWithErrors, "Server buffer malloc failed");
}
while ((echoData && throughput == 0) ||
(!echoData && xfer_bytes < throughput))
{
select_ret = tcp_select(clientfd, 1); /* Timeout=1 second */
if (select_ret == TEST_RECV_READY) {
len = min(TEST_BUFFER_SIZE, throughput - xfer_bytes);
rx_pos = 0;
if (throughput) {
start = current_time(1);
}
/* Read data */
while (rx_pos < len) {
ret = SSL_read(ssl, &buffer[rx_pos], len - rx_pos);
if (ret < 0) {
err = SSL_get_error(ssl, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
else
#endif
if (err != SSL_ERROR_WANT_READ) {
printf("SSL_read echo error %d\n", err);
err_sys_ex(runWithErrors, "SSL_read failed");
}
}
else {
rx_pos += ret;
}
}
if (throughput) {
rx_time += current_time(0) - start;
start = current_time(1);
}
/* Write data */
do {
err = 0; /* reset error */
ret = SSL_write(ssl, buffer, len);
if (ret <= 0) {
err = SSL_get_error(ssl, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
}
} while (err == WC_PENDING_E);
if (ret != len) {
printf("SSL_write echo error %d\n", err);
err_sys_ex(runWithErrors, "SSL_write failed");
}
if (throughput) {
tx_time += current_time(0) - start;
}
xfer_bytes += len;
}
}
free(buffer);
if (throughput) {
printf("wolfSSL Server Benchmark %d bytes\n"
"\tRX %8.3f ms (%8.3f MBps)\n"
"\tTX %8.3f ms (%8.3f MBps)\n",
throughput,
tx_time * 1000, throughput / tx_time / 1024 / 1024,
rx_time * 1000, throughput / rx_time / 1024 / 1024
);
}
return EXIT_SUCCESS;
}
static void ServerRead(WOLFSSL* ssl, char* input, int inputLen)
{
int ret, err;
char buffer[CYASSL_MAX_ERROR_SZ];
/* Read data */
do {
err = 0; /* reset error */
ret = SSL_read(ssl, input, inputLen);
if (ret < 0) {
err = SSL_get_error(ssl, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
else
#endif
if (err != SSL_ERROR_WANT_READ) {
printf("SSL_read input error %d, %s\n", err,
ERR_error_string(err, buffer));
err_sys_ex(runWithErrors, "SSL_read failed");
}
}
} while (err == WC_PENDING_E);
if (ret > 0) {
input[ret] = 0; /* null terminate message */
printf("Client message: %s\n", input);
}
}
static void ServerWrite(WOLFSSL* ssl, const char* output, int outputLen)
{
int ret, err;
char buffer[CYASSL_MAX_ERROR_SZ];
do {
err = 0; /* reset error */
ret = SSL_write(ssl, output, outputLen);
if (ret <= 0) {
err = SSL_get_error(ssl, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
}
} while (err == WC_PENDING_E || err == SSL_ERROR_WANT_WRITE);
if (ret != outputLen) {
printf("SSL_write msg error %d, %s\n", err,
ERR_error_string(err, buffer));
err_sys_ex(runWithErrors, "SSL_write failed");
}
}
static void Usage(void)
{
printf("server " LIBCYASSL_VERSION_STRING
" NOTE: All files relative to wolfSSL home dir\n");
printf("-? Help, print this usage\n");
printf("-p <num> Port to listen on, not 0, default %d\n", yasslPort);
#ifndef WOLFSSL_TLS13
printf("-v <num> SSL version [0-3], SSLv3(0) - TLS1.2(3)), default %d\n",
SERVER_DEFAULT_VERSION);
#else
printf("-v <num> SSL version [0-4], SSLv3(0) - TLS1.3(4)), default %d\n",
SERVER_DEFAULT_VERSION);
#endif
printf("-l <str> Cipher suite list (: delimited)\n");
printf("-c <file> Certificate file, default %s\n", svrCertFile);
printf("-k <file> Key file, default %s\n", svrKeyFile);
printf("-A <file> Certificate Authority file, default %s\n", cliCertFile);
printf("-R <file> Create Ready file for external monitor default none\n");
#ifndef NO_DH
printf("-D <file> Diffie-Hellman Params file, default %s\n", dhParamFile);
printf("-Z <num> Minimum DH key bits, default %d\n",
DEFAULT_MIN_DHKEY_BITS);
#endif
#ifdef HAVE_ALPN
printf("-L <str> Application-Layer Protocol Negotiation ({C,F}:<list>)\n");
#endif
printf("-d Disable client cert check\n");
printf("-b Bind to any interface instead of localhost only\n");
printf("-s Use pre Shared keys\n");
printf("-u Use UDP DTLS,"
" add -v 2 for DTLSv1, -v 3 for DTLSv1.2 (default)\n");
#ifdef WOLFSSL_SCTP
printf("-G Use SCTP DTLS,"
" add -v 2 for DTLSv1, -v 3 for DTLSv1.2 (default)\n");
#endif
printf("-f Fewer packets/group messages\n");
printf("-r Allow one client Resumption\n");
printf("-N Use Non-blocking sockets\n");
printf("-S <str> Use Host Name Indication\n");
printf("-w Wait for bidirectional shutdown\n");
#ifdef HAVE_OCSP
printf("-o Perform OCSP lookup on peer certificate\n");
printf("-O <url> Perform OCSP lookup using <url> as responder\n");
#endif
#ifdef HAVE_PK_CALLBACKS
printf("-P Public Key Callbacks\n");
#endif
#ifdef HAVE_ANON
printf("-a Anonymous server\n");
#endif
#ifndef NO_PSK
printf("-I Do not send PSK identity hint\n");
#endif
printf("-x Print server errors but do not close connection\n");
printf("-i Loop indefinitely (allow repeated connections)\n");
printf("-e Echo data mode (return raw bytes received)\n");
#ifdef HAVE_NTRU
printf("-n Use NTRU key (needed for NTRU suites)\n");
#endif
printf("-B <num> Benchmark throughput using <num> bytes and print stats\n");
#ifdef WOLFSSL_TRUST_PEER_CERT
printf("-E <file> Path to load trusted peer cert\n");
#endif
#ifdef HAVE_WNR
printf("-q <file> Whitewood config file, default %s\n", wnrConfig);
#endif
printf("-g Return basic HTML web page\n");
printf("-C <num> The number of connections to accept, default: 1\n");
printf("-H Force use of the default cipher suite list\n");
#ifdef WOLFSSL_TLS13
printf("-K Key Exchange for PSK not using (EC)DHE\n");
printf("-U Update keys and IVs before sending\n");
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
printf("-Q Request certificate from client post-handshake\n");
#endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
printf("-J Server sends Cookie Extension containing state\n");
#endif
#endif
#ifdef WOLFSSL_EARLY_DATA
printf("-0 Early data read from client (0-RTT handshake)\n");
#endif
}
THREAD_RETURN CYASSL_THREAD server_test(void* args)
{
SOCKET_T sockfd = WOLFSSL_SOCKET_INVALID;
SOCKET_T clientfd = WOLFSSL_SOCKET_INVALID;
wolfSSL_method_func method = NULL;
SSL_CTX* ctx = 0;
SSL* ssl = 0;
#ifndef WOLFSSL_ALT_TEST_STRINGS
const char msg[] = "I hear you fa shizzle!";
#else
const char msg[] = "I hear you fa shizzle!\n";
#endif
int useWebServerMsg = 0;
char input[80];
int ch;
int version = SERVER_DEFAULT_VERSION;
int doCliCertCheck = 1;
int useAnyAddr = 0;
word16 port = wolfSSLPort;
int usePsk = 0;
int usePskPlus = 0;
int useAnon = 0;
int doDTLS = 0;
int dtlsUDP = 0;
int dtlsSCTP = 0;
int needDH = 0;
int useNtruKey = 0;
int nonBlocking = 0;
int fewerPackets = 0;
int pkCallbacks = 0;
int wc_shutdown = 0;
int resume = 0;
int resumeCount = 0;
int loops = 1;
int echoData = 0;
int throughput = 0;
int minDhKeyBits = DEFAULT_MIN_DHKEY_BITS;
short minRsaKeyBits = DEFAULT_MIN_RSAKEY_BITS;
short minEccKeyBits = DEFAULT_MIN_ECCKEY_BITS;
int doListen = 1;
int crlFlags = 0;
int ret;
int err = 0;
char* serverReadyFile = NULL;
char* alpnList = NULL;
unsigned char alpn_opt = 0;
char* cipherList = NULL;
int useDefCipherList = 0;
const char* verifyCert = cliCertFile;
const char* ourCert = svrCertFile;
const char* ourKey = svrKeyFile;
const char* ourDhParam = dhParamFile;
tcp_ready* readySignal = NULL;
int argc = ((func_args*)args)->argc;
char** argv = ((func_args*)args)->argv;
#ifdef WOLFSSL_TRUST_PEER_CERT
const char* trustCert = NULL;
#endif
#ifndef NO_PSK
int sendPskIdentityHint = 1;
#endif
#ifdef HAVE_SNI
char* sniHostName = NULL;
#endif
#ifdef HAVE_OCSP
int useOcsp = 0;
char* ocspUrl = NULL;
#endif
#ifdef HAVE_WNR
const char* wnrConfigFile = wnrConfig;
#endif
char buffer[CYASSL_MAX_ERROR_SZ];
#ifdef WOLFSSL_TLS13
int noPskDheKe = 0;
#endif
int updateKeysIVs = 0;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
int postHandAuth = 0;
#endif
#ifdef WOLFSSL_EARLY_DATA
int earlyData = 0;
#endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
int hrrCookie = 0;
#endif
#ifdef WOLFSSL_STATIC_MEMORY
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \
|| defined(SESSION_CERTS)
/* big enough to handle most cases including session certs */
byte memory[204000];
#else
byte memory[80000];
#endif
byte memoryIO[34500]; /* max of 17k for IO buffer (TLS packet can be 16k) */
WOLFSSL_MEM_CONN_STATS ssl_stats;
#endif
((func_args*)args)->return_code = -1; /* error state */
#ifdef NO_RSA
verifyCert = (char*)cliEccCertFile;
ourCert = (char*)eccCertFile;
ourKey = (char*)eccKeyFile;
#endif
(void)pkCallbacks;
(void)needDH;
(void)ourKey;
(void)ourCert;
(void)ourDhParam;
(void)verifyCert;
(void)useNtruKey;
(void)doCliCertCheck;
(void)minDhKeyBits;
(void)minRsaKeyBits;
(void)minEccKeyBits;
(void)alpnList;
(void)alpn_opt;
(void)crlFlags;
(void)readySignal;
(void)updateKeysIVs;
#ifdef CYASSL_TIRTOS
fdOpenSession(Task_self());
#endif
#ifdef WOLFSSL_VXWORKS
useAnyAddr = 1;
#else
/* Not Used: h, m, t, y, z, F, M, T, V, W, X, Y */
while ((ch = mygetopt(argc, argv, "?"
"abc:defgijk:l:nop:q:rsuv:wx"
"A:B:C:D:E:GHIJKL:NO:PQR:S:UYZ:"
"0")) != -1) {
switch (ch) {
case '?' :
Usage();
exit(EXIT_SUCCESS);
case 'x' :
runWithErrors = 1;
break;
case 'd' :
doCliCertCheck = 0;
break;
case 'b' :
useAnyAddr = 1;
break;
case 's' :
usePsk = 1;
break;
case 'j' :
usePskPlus = 1;
break;
case 'n' :
useNtruKey = 1;
break;
case 'u' :
doDTLS = 1;
dtlsUDP = 1;
break;
case 'G' :
#ifdef WOLFSSL_SCTP
doDTLS = 1;
dtlsSCTP = 1;
#endif
break;
case 'f' :
fewerPackets = 1;
break;
case 'R' :
serverReadyFile = myoptarg;
break;
case 'r' :
#ifndef NO_SESSION_CACHE
resume = 1;
#endif
break;
case 'P' :
#ifdef HAVE_PK_CALLBACKS
pkCallbacks = 1;
#endif
break;
case 'p' :
port = (word16)atoi(myoptarg);
break;
case 'w' :
wc_shutdown = 1;
break;
case 'v' :
version = atoi(myoptarg);
if (version < 0 || version > 4) {
Usage();
exit(MY_EX_USAGE);
}
break;
case 'l' :
cipherList = myoptarg;
break;
case 'H' :
useDefCipherList = 1;
break;
case 'A' :
verifyCert = myoptarg;
break;
case 'c' :
ourCert = myoptarg;
break;
case 'k' :
ourKey = myoptarg;
break;
case 'D' :
#ifndef NO_DH
ourDhParam = myoptarg;
#endif
break;
case 'Z' :
#ifndef NO_DH
minDhKeyBits = atoi(myoptarg);
if (minDhKeyBits <= 0 || minDhKeyBits > 16000) {
Usage();
exit(MY_EX_USAGE);
}
#endif
break;
case 'N':
nonBlocking = 1;
break;
case 'S' :
#ifdef HAVE_SNI
sniHostName = myoptarg;
#endif
break;
case 'o' :
#ifdef HAVE_OCSP
useOcsp = 1;
#endif
break;
case 'O' :
#ifdef HAVE_OCSP
useOcsp = 1;
ocspUrl = myoptarg;
#endif
break;
case 'a' :
#ifdef HAVE_ANON
useAnon = 1;
#endif
break;
case 'I':
#ifndef NO_PSK
sendPskIdentityHint = 0;
#endif
break;
case 'L' :
#ifdef HAVE_ALPN
alpnList = myoptarg;
if (alpnList[0] == 'C' && alpnList[1] == ':')
alpn_opt = WOLFSSL_ALPN_CONTINUE_ON_MISMATCH;
else if (alpnList[0] == 'F' && alpnList[1] == ':')
alpn_opt = WOLFSSL_ALPN_FAILED_ON_MISMATCH;
else {
Usage();
exit(MY_EX_USAGE);
}
alpnList += 2;
#endif
break;
case 'i' :
loops = -1;
break;
case 'C' :
loops = atoi(myoptarg);
if (loops <= 0) {
Usage();
exit(MY_EX_USAGE);
}
break;
case 'e' :
echoData = 1;
break;
case 'B':
throughput = atoi(myoptarg);
if (throughput <= 0) {
Usage();
exit(MY_EX_USAGE);
}
break;
#ifdef WOLFSSL_TRUST_PEER_CERT
case 'E' :
trustCert = myoptarg;
break;
#endif
case 'q' :
#ifdef HAVE_WNR
wnrConfigFile = myoptarg;
#endif
break;
case 'g' :
useWebServerMsg = 1;
break;
case 'K' :
#ifdef WOLFSSL_TLS13
noPskDheKe = 1;
#endif
break;
case 'U' :
#ifdef WOLFSSL_TLS13
updateKeysIVs = 1;
#endif
break;
case 'Q' :
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
postHandAuth = 1;
doCliCertCheck = 0;
#endif
break;
case 'J' :
#ifdef WOLFSSL_SEND_HRR_COOKIE
hrrCookie = 1;
#endif
break;
case '0' :
#ifdef WOLFSSL_EARLY_DATA
earlyData = 1;
#endif
break;
default:
Usage();
exit(MY_EX_USAGE);
}
}
myoptind = 0; /* reset for test cases */
#endif /* !WOLFSSL_VXWORKS */
/* Can only use DTLS over UDP or SCTP, can't do both. */
if (dtlsUDP && dtlsSCTP) {
err_sys_ex(runWithErrors, "Cannot use DTLS with both UDP and SCTP.");
}
/* sort out DTLS versus TLS versions */
if (version == CLIENT_INVALID_VERSION) {
if (doDTLS)
version = CLIENT_DTLS_DEFAULT_VERSION;
else
version = CLIENT_DEFAULT_VERSION;
}
else {
if (doDTLS) {
if (version == 3)
version = -2;
else
version = -1;
}
}
#ifdef HAVE_WNR
if (wc_InitNetRandom(wnrConfigFile, NULL, 5000) != 0)
err_sys_ex(runWithErrors, "can't load whitewood net random config file");
#endif
switch (version) {
#ifndef NO_OLD_TLS
#ifdef WOLFSSL_ALLOW_SSLV3
case 0:
method = wolfSSLv3_server_method_ex;
break;
#endif
#ifndef NO_TLS
case 1:
method = wolfTLSv1_server_method_ex;
break;
case 2:
method = wolfTLSv1_1_server_method_ex;
break;
#endif
#endif
#ifndef NO_TLS
case 3:
method = wolfTLSv1_2_server_method_ex;
break;
#endif
#ifdef WOLFSSL_TLS13
case 4:
method = wolfTLSv1_3_server_method_ex;
break;
#endif
#ifdef CYASSL_DTLS
#ifndef NO_OLD_TLS
case -1:
method = wolfDTLSv1_server_method_ex;
break;
#endif
case -2:
method = wolfDTLSv1_2_server_method_ex;
break;
#endif
default:
err_sys_ex(runWithErrors, "Bad SSL version");
}
if (method == NULL)
err_sys_ex(runWithErrors, "unable to get method");
#ifdef WOLFSSL_STATIC_MEMORY
#ifdef DEBUG_WOLFSSL
/* print off helper buffer sizes for use with static memory
* printing to stderr incase of debug mode turned on */
fprintf(stderr, "static memory management size = %d\n",
wolfSSL_MemoryPaddingSz());
fprintf(stderr, "calculated optimum general buffer size = %d\n",
wolfSSL_StaticBufferSz(memory, sizeof(memory), 0));
fprintf(stderr, "calculated optimum IO buffer size = %d\n",
wolfSSL_StaticBufferSz(memoryIO, sizeof(memoryIO),
WOLFMEM_IO_POOL_FIXED));
#endif /* DEBUG_WOLFSSL */
if (wolfSSL_CTX_load_static_memory(&ctx, method, memory, sizeof(memory),0,1)
!= SSL_SUCCESS)
err_sys_ex(runWithErrors, "unable to load static memory and create ctx");
/* load in a buffer for IO */
if (wolfSSL_CTX_load_static_memory(&ctx, NULL, memoryIO, sizeof(memoryIO),
WOLFMEM_IO_POOL_FIXED | WOLFMEM_TRACK_STATS, 1)
!= SSL_SUCCESS)
err_sys_ex(runWithErrors, "unable to load static memory and create ctx");
#else
ctx = SSL_CTX_new(method(NULL));
#endif /* WOLFSSL_STATIC_MEMORY */
if (ctx == NULL)
err_sys_ex(runWithErrors, "unable to get ctx");
#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \
defined(HAVE_POLY1305)
if (TicketInit() != 0)
err_sys_ex(runWithErrors, "unable to setup Session Ticket Key context");
wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb);
#endif
if (cipherList && !useDefCipherList) {
if (SSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "server can't set cipher list 1");
}
#ifdef CYASSL_LEANPSK
if (!usePsk) {
usePsk = 1;
}
#endif
#if defined(NO_RSA) && !defined(HAVE_ECC)
if (!usePsk) {
usePsk = 1;
}
#endif
if (fewerPackets)
CyaSSL_CTX_set_group_messages(ctx);
#ifdef WOLFSSL_SCTP
if (dtlsSCTP)
wolfSSL_CTX_dtls_set_sctp(ctx);
#endif
#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif
#if !defined(NO_CERTS)
if ((!usePsk || usePskPlus) && !useAnon) {
#if !defined(NO_FILESYSTEM)
if (SSL_CTX_use_certificate_chain_file(ctx, ourCert)
!= SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't load server cert file, check file and run from"
" wolfSSL home dir");
#else
/* loads cert chain file using buffer API */
load_buffer(ctx, ourCert, WOLFSSL_CERT_CHAIN);
#endif
}
#endif
#ifndef NO_DH
if (wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits) != SSL_SUCCESS) {
err_sys_ex(runWithErrors, "Error setting minimum DH key size");
}
#endif
#ifndef NO_RSA
if (wolfSSL_CTX_SetMinRsaKey_Sz(ctx, minRsaKeyBits) != SSL_SUCCESS){
err_sys_ex(runWithErrors, "Error setting minimum RSA key size");
}
#endif
#ifdef HAVE_ECC
if (wolfSSL_CTX_SetMinEccKey_Sz(ctx, minEccKeyBits) != SSL_SUCCESS){
err_sys_ex(runWithErrors, "Error setting minimum ECC key size");
}
#endif
#ifdef HAVE_NTRU
if (useNtruKey) {
if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ourKey)
!= SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't load ntru key file, "
"Please run from wolfSSL home dir");
}
#endif
#if !defined(NO_CERTS)
if (!useNtruKey && (!usePsk || usePskPlus) && !useAnon) {
#if !defined(NO_FILESYSTEM)
if (SSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM)
!= SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't load server private key file, check file and run "
"from wolfSSL home dir");
#else
/* loads private key file using buffer API */
load_buffer(ctx, ourKey, WOLFSSL_KEY);
#endif
}
#endif
if (usePsk || usePskPlus) {
#ifndef NO_PSK
SSL_CTX_set_psk_server_callback(ctx, my_psk_server_cb);
if (sendPskIdentityHint == 1)
SSL_CTX_use_psk_identity_hint(ctx, "cyassl server");
if (cipherList == NULL && !usePskPlus) {
const char *defaultCipherList;
#if defined(HAVE_AESGCM) && !defined(NO_DH)
#ifdef WOLFSSL_TLS13
defaultCipherList = "DHE-PSK-AES128-GCM-SHA256:"
"TLS13-AES128-GCM-SHA256";
#else
defaultCipherList = "DHE-PSK-AES128-GCM-SHA256";
#endif
needDH = 1;
#elif defined(HAVE_NULL_CIPHER)
defaultCipherList = "PSK-NULL-SHA256";
#else
defaultCipherList = "PSK-AES128-CBC-SHA256";
#endif
if (SSL_CTX_set_cipher_list(ctx, defaultCipherList) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "server can't set cipher list 2");
}
#endif
}
if (useAnon) {
#ifdef HAVE_ANON
CyaSSL_CTX_allow_anon_cipher(ctx);
if (cipherList == NULL || (cipherList && useDefCipherList)) {
if (SSL_CTX_set_cipher_list(ctx, "ADH-AES128-SHA") != SSL_SUCCESS)
err_sys_ex(runWithErrors, "server can't set cipher list 4");
}
#endif
}
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
/* if not using PSK, verify peer with certs
if using PSK Plus then verify peer certs except PSK suites */
if (doCliCertCheck && (usePsk == 0 || usePskPlus) && useAnon == 0) {
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER |
((usePskPlus)? SSL_VERIFY_FAIL_EXCEPT_PSK :
SSL_VERIFY_FAIL_IF_NO_PEER_CERT),0);
if (SSL_CTX_load_verify_locations(ctx, verifyCert, 0) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't load ca file, Please run from wolfSSL home dir");
#ifdef WOLFSSL_TRUST_PEER_CERT
if (trustCert) {
if ((ret = wolfSSL_CTX_trust_peer_cert(ctx, trustCert,
SSL_FILETYPE_PEM)) != SSL_SUCCESS) {
err_sys_ex(runWithErrors, "can't load trusted peer cert file");
}
}
#endif /* WOLFSSL_TRUST_PEER_CERT */
}
#endif
#if defined(CYASSL_SNIFFER)
/* don't use EDH, can't sniff tmp keys */
if (cipherList == NULL) {
if (SSL_CTX_set_cipher_list(ctx, "AES128-SHA") != SSL_SUCCESS)
err_sys_ex(runWithErrors, "server can't set cipher list 3");
}
#endif
#ifdef HAVE_SNI
if (sniHostName)
if (CyaSSL_CTX_UseSNI(ctx, CYASSL_SNI_HOST_NAME, sniHostName,
XSTRLEN(sniHostName)) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "UseSNI failed");
#endif
#ifdef USE_WINDOWS_API
if (port == 0) {
/* Generate random port for testing */
port = GetRandomPort();
}
#endif /* USE_WINDOWS_API */
#ifdef WOLFSSL_ASYNC_CRYPT
ret = wolfAsync_DevOpen(&devId);
if (ret < 0) {
printf("Async device open failed\nRunning without async\n");
}
wolfSSL_CTX_UseAsync(ctx, devId);
#endif /* WOLFSSL_ASYNC_CRYPT */
#ifdef WOLFSSL_TLS13
if (noPskDheKe)
wolfSSL_CTX_no_dhe_psk(ctx);
#endif
while (1) {
/* allow resume option */
if (resumeCount > 1) {
if (dtlsUDP == 0) {
SOCKADDR_IN_T client;
socklen_t client_len = sizeof(client);
clientfd = accept(sockfd, (struct sockaddr*)&client,
(ACCEPT_THIRD_T)&client_len);
}
else {
tcp_listen(&sockfd, &port, useAnyAddr, dtlsUDP, dtlsSCTP);
clientfd = sockfd;
}
if (WOLFSSL_SOCKET_IS_INVALID(clientfd)) {
err_sys_ex(runWithErrors, "tcp accept failed");
}
}
#if defined(WOLFSSL_STATIC_MEMORY) && defined(DEBUG_WOLFSSL)
{
WOLFSSL_MEM_STATS mem_stats;
fprintf(stderr, "Before creating SSL\n");
if (wolfSSL_CTX_is_static_memory(ctx, &mem_stats) != 1)
err_sys_ex(runWithErrors, "ctx not using static memory");
if (wolfSSL_PrintStats(&mem_stats) != 1) /* function in test.h */
err_sys_ex(runWithErrors, "error printing out memory stats");
}
#endif
ssl = SSL_new(ctx);
if (ssl == NULL)
err_sys_ex(runWithErrors, "unable to get SSL");
#ifdef OPENSSL_EXTRA
wolfSSL_KeepArrays(ssl);
#endif
#ifdef WOLFSSL_SEND_HRR_COOKIE
if (hrrCookie && wolfSSL_send_hrr_cookie(ssl, NULL, 0) != SSL_SUCCESS) {
err_sys("unable to set use of cookie with HRR msg");
}
#endif
#if defined(WOLFSSL_STATIC_MEMORY) && defined(DEBUG_WOLFSSL)
{
WOLFSSL_MEM_STATS mem_stats;
fprintf(stderr, "After creating SSL\n");
if (wolfSSL_CTX_is_static_memory(ctx, &mem_stats) != 1)
err_sys_ex(runWithErrors, "ctx not using static memory");
if (wolfSSL_PrintStats(&mem_stats) != 1) /* function in test.h */
err_sys_ex(runWithErrors, "error printing out memory stats");
}
#endif
#ifndef NO_HANDSHAKE_DONE_CB
wolfSSL_SetHsDoneCb(ssl, myHsDoneCb, NULL);
#endif
#ifdef HAVE_CRL
#ifdef HAVE_CRL_MONITOR
crlFlags = CYASSL_CRL_MONITOR | CYASSL_CRL_START_MON;
#endif
if (CyaSSL_EnableCRL(ssl, 0) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "unable to enable CRL");
if (CyaSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, crlFlags)
!= SSL_SUCCESS)
err_sys_ex(runWithErrors, "unable to load CRL");
if (CyaSSL_SetCRL_Cb(ssl, CRL_CallBack) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "unable to set CRL callback url");
#endif
#ifdef HAVE_OCSP
if (useOcsp) {
if (ocspUrl != NULL) {
CyaSSL_CTX_SetOCSP_OverrideURL(ctx, ocspUrl);
CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE
| CYASSL_OCSP_URL_OVERRIDE);
}
else
CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE);
}
#endif
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
|| defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (wolfSSL_CTX_EnableOCSPStapling(ctx) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't enable OCSP Stapling Certificate Manager");
if (SSL_CTX_load_verify_locations(ctx, "certs/ocsp/intermediate1-ca-cert.pem", 0) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't load ca file, Please run from wolfSSL home dir");
if (SSL_CTX_load_verify_locations(ctx, "certs/ocsp/intermediate2-ca-cert.pem", 0) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't load ca file, Please run from wolfSSL home dir");
if (SSL_CTX_load_verify_locations(ctx, "certs/ocsp/intermediate3-ca-cert.pem", 0) != SSL_SUCCESS)
err_sys_ex(runWithErrors, "can't load ca file, Please run from wolfSSL home dir");
#endif
#ifdef HAVE_PK_CALLBACKS
if (pkCallbacks)
SetupPkCallbacks(ctx, ssl);
#endif
/* do accept */
readySignal = ((func_args*)args)->signal;
if (readySignal) {
readySignal->srfName = serverReadyFile;
}
tcp_accept(&sockfd, &clientfd, (func_args*)args, port, useAnyAddr,
dtlsUDP, dtlsSCTP, serverReadyFile ? 1 : 0, doListen);
doListen = 0; /* Don't listen next time */
if (SSL_set_fd(ssl, clientfd) != SSL_SUCCESS) {
err_sys_ex(runWithErrors, "error in setting fd");
}
#ifdef HAVE_ALPN
if (alpnList != NULL) {
printf("ALPN accepted protocols list : %s\n", alpnList);
wolfSSL_UseALPN(ssl, alpnList, (word32)XSTRLEN(alpnList), alpn_opt);
}
#endif
#ifdef WOLFSSL_DTLS
if (doDTLS && dtlsUDP) {
SOCKADDR_IN_T cliaddr;
byte b[1500];
int n;
socklen_t len = sizeof(cliaddr);
/* For DTLS, peek at the next datagram so we can get the client's
* address and set it into the ssl object later to generate the
* cookie. */
n = (int)recvfrom(sockfd, (char*)b, sizeof(b), MSG_PEEK,
(struct sockaddr*)&cliaddr, &len);
if (n <= 0)
err_sys_ex(runWithErrors, "recvfrom failed");
wolfSSL_dtls_set_peer(ssl, &cliaddr, len);
}
#endif
if ((usePsk == 0 || usePskPlus) || useAnon == 1 || cipherList != NULL
|| needDH == 1) {
#if !defined(NO_FILESYSTEM) && !defined(NO_DH) && !defined(NO_ASN)
CyaSSL_SetTmpDH_file(ssl, ourDhParam, SSL_FILETYPE_PEM);
#elif !defined(NO_DH)
SetDH(ssl); /* repick suites with DHE, higher priority than PSK */
#endif
}
#ifndef CYASSL_CALLBACKS
if (nonBlocking) {
CyaSSL_set_using_nonblock(ssl, 1);
tcp_set_nonblocking(&clientfd);
}
#endif
#ifndef CYASSL_CALLBACKS
if (nonBlocking) {
ret = NonBlockingSSL_Accept(ssl);
}
else {
#ifdef WOLFSSL_EARLY_DATA
if (earlyData) {
do {
int len;
err = 0; /* reset error */
ret = wolfSSL_read_early_data(ssl, input, sizeof(input)-1,
&len);
if (ret != SSL_SUCCESS) {
err = SSL_get_error(ssl, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
}
if (ret > 0) {
input[ret] = 0; /* null terminate message */
printf("Early Data Client message: %s\n", input);
}
} while (err == WC_PENDING_E || ret > 0);
}
#endif
do {
err = 0; /* reset error */
ret = SSL_accept(ssl);
if (ret != SSL_SUCCESS) {
err = SSL_get_error(ssl, 0);
#ifdef WOLFSSL_ASYNC_CRYPT
if (err == WC_PENDING_E) {
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
if (ret < 0) break;
}
#endif
}
} while (err == WC_PENDING_E);
}
#else
ret = NonBlockingSSL_Accept(ssl);
#endif
if (ret != SSL_SUCCESS) {
err = SSL_get_error(ssl, 0);
printf("SSL_accept error %d, %s\n", err,
ERR_error_string(err, buffer));
err_sys_ex(runWithErrors, "SSL_accept failed");
}
showPeer(ssl);
if (SSL_state(ssl) != 0) {
err_sys_ex(runWithErrors, "SSL in error state");
}
#ifdef OPENSSL_EXTRA
{
byte* rnd;
byte* pt;
size_t size;
/* get size of buffer then print */
size = wolfSSL_get_server_random(NULL, NULL, 0);
if (size == 0) {
err_sys_ex(runWithErrors, "error getting server random buffer size");
}
rnd = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (rnd == NULL) {
err_sys_ex(runWithErrors, "error creating server random buffer");
}
size = wolfSSL_get_server_random(ssl, rnd, size);
if (size == 0) {
XFREE(rnd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
err_sys_ex(runWithErrors, "error getting server random buffer");
}
printf("Server Random : ");
pt = rnd;
if (pt != NULL) {
for (pt = rnd; pt < rnd + size; pt++) printf("%02X", *pt);
printf("\n");
} else {
err_sys_ex(runWithErrors, "error: attempted to dereference null "
"pointer");
}
XFREE(rnd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
#ifdef HAVE_ALPN
if (alpnList != NULL) {
char *protocol_name = NULL, *list = NULL;
word16 protocol_nameSz = 0, listSz = 0;
err = wolfSSL_ALPN_GetProtocol(ssl, &protocol_name, &protocol_nameSz);
if (err == SSL_SUCCESS)
printf("Sent ALPN protocol : %s (%d)\n",
protocol_name, protocol_nameSz);
else if (err == SSL_ALPN_NOT_FOUND)
printf("No ALPN response sent (no match)\n");
else
printf("Getting ALPN protocol name failed\n");
err = wolfSSL_ALPN_GetPeerProtocol(ssl, &list, &listSz);
if (err == SSL_SUCCESS)
printf("List of protocol names sent by Client: %s (%d)\n",
list, listSz);
else
printf("Get list of client's protocol name failed\n");
free(list);
}
#endif
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
if (postHandAuth) {
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER |
((usePskPlus)? SSL_VERIFY_FAIL_EXCEPT_PSK :
SSL_VERIFY_FAIL_IF_NO_PEER_CERT),0);
if (SSL_CTX_load_verify_locations(ctx, verifyCert, 0)
!= SSL_SUCCESS) {
err_sys_ex(runWithErrors, "can't load ca file, Please run from wolfSSL home dir");
}
#ifdef WOLFSSL_TRUST_PEER_CERT
if (trustCert) {
if ((ret = wolfSSL_CTX_trust_peer_cert(ctx, trustCert,
SSL_FILETYPE_PEM)) != SSL_SUCCESS) {
err_sys_ex(runWithErrors, "can't load trusted peer cert file");
}
}
#endif /* WOLFSSL_TRUST_PEER_CERT */
}
#endif
#endif
if (echoData == 0 && throughput == 0) {
const char* write_msg;
int write_msg_sz;
ServerRead(ssl, input, sizeof(input)-1);
#ifdef WOLFSSL_TLS13
if (updateKeysIVs)
wolfSSL_update_keys(ssl);
#endif
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
if (postHandAuth)
wolfSSL_request_certificate(ssl);
#endif
/* Write data */
if (!useWebServerMsg) {
write_msg = msg;
write_msg_sz = sizeof(msg);
}
else {
write_msg = webServerMsg;
write_msg_sz = sizeof(webServerMsg);
}
ServerWrite(ssl, write_msg, write_msg_sz);
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
if (postHandAuth) {
ServerWrite(ssl, write_msg, write_msg_sz);
ServerRead(ssl, input, sizeof(input)-1);
}
#endif
}
else {
ServerEchoData(ssl, clientfd, echoData, throughput);
}
#if defined(WOLFSSL_MDK_SHELL) && defined(HAVE_MDK_RTX)
os_dly_wait(500) ;
#elif defined (CYASSL_TIRTOS)
Task_yield();
#endif
if (dtlsUDP == 0) {
ret = SSL_shutdown(ssl);
if (wc_shutdown && ret == SSL_SHUTDOWN_NOT_DONE)
SSL_shutdown(ssl); /* bidirectional shutdown */
}
/* display collected statistics */
#ifdef WOLFSSL_STATIC_MEMORY
if (wolfSSL_is_static_memory(ssl, &ssl_stats) != 1)
err_sys_ex(runWithErrors, "static memory was not used with ssl");
fprintf(stderr, "\nprint off SSL memory stats\n");
fprintf(stderr, "*** This is memory state before wolfSSL_free is called\n");
fprintf(stderr, "peak connection memory = %d\n", ssl_stats.peakMem);
fprintf(stderr, "current memory in use = %d\n", ssl_stats.curMem);
fprintf(stderr, "peak connection allocs = %d\n", ssl_stats.peakAlloc);
fprintf(stderr, "current connection allocs = %d\n",ssl_stats.curAlloc);
fprintf(stderr, "total connection allocs = %d\n",ssl_stats.totalAlloc);
fprintf(stderr, "total connection frees = %d\n\n", ssl_stats.totalFr);
#endif
SSL_free(ssl);
CloseSocket(clientfd);
if (resume == 1 && resumeCount == 0) {
resumeCount++; /* only do one resume for testing */
continue;
}
resumeCount = 0;
if (loops > 0 && --loops == 0) {
break; /* out of while loop, done with normal and resume option */
}
} /* while(1) */
CloseSocket(sockfd);
SSL_CTX_free(ctx);
((func_args*)args)->return_code = 0;
#if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
&& defined(HAVE_THREAD_LS)
ecc_fp_free(); /* free per thread cache */
#endif
#ifdef CYASSL_TIRTOS
fdCloseSession(Task_self());
#endif
#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \
defined(HAVE_POLY1305)
TicketCleanup();
#endif
#ifdef WOLFSSL_ASYNC_CRYPT
wolfAsync_DevClose(&devId);
#endif
/* There are use cases when these assignments are not read. To avoid
* potential confusion those warnings have been handled here.
*/
(void) ourKey;
(void) verifyCert;
(void) doCliCertCheck;
(void) useNtruKey;
(void) ourDhParam;
(void) ourCert;
#ifndef CYASSL_TIRTOS
return 0;
#endif
}
#endif /* !NO_WOLFSSL_SERVER */
/* so overall tests can pull in test function */
#ifndef NO_MAIN_DRIVER
int main(int argc, char** argv)
{
func_args args;
tcp_ready ready;
StartTCP();
args.argc = argc;
args.argv = argv;
args.signal = &ready;
InitTcpReady(&ready);
#if defined(DEBUG_CYASSL) && !defined(WOLFSSL_MDK_SHELL)
CyaSSL_Debugging_ON();
#endif
CyaSSL_Init();
ChangeToWolfRoot();
#ifndef NO_WOLFSSL_SERVER
#ifdef HAVE_STACK_SIZE
StackSizeCheck(&args, server_test);
#else
server_test(&args);
#endif
#else
printf("Server not compiled in!\n");
#endif
CyaSSL_Cleanup();
FreeTcpReady(&ready);
#ifdef HAVE_WNR
if (wc_FreeNetRandom() < 0)
err_sys_ex(runWithErrors, "Failed to free netRandom context");
#endif /* HAVE_WNR */
return args.return_code;
}
int myoptind = 0;
char* myoptarg = NULL;
#endif /* NO_MAIN_DRIVER */