#include #include #include #include #include #include #include #include #include #include #include #include "wolfExamples.h" #include #include #include #include #include /***************************************************************************** * Globals ****************************************************************************/ RTHANDLE hRootProcess; DWORD dwKtickInUsecs; INIT_STRUCT gInit; static int gServerExit = 0; static int gServerReady = 0; static const char menu1[] = "\r\n" "\tt. WolfCrypt Test\r\n" "\tb. WolfCrypt Benchmark\r\n" "\tc. WolfSSL Client Example\r\n" "\ts. WolfSSL Server Example\r\n" "\tl. WolfSSL Localhost Client/Server Example\r\n"; /***************************************************************************** * Configuration ****************************************************************************/ #define TLS_MAXDATASIZE 4096 /* maximum acceptable amount of data */ #define TLS_PORT 11111 /* define default port number */ #define TLS_HOST_LOCAL "127.0.0.1" #define TLS_HOST_REMOTE "192.168.0.112" #define SOCK_MAX_PENDING 5 #define THREAD_BASE_PRIO 150 /***************************************************************************** * TLS Client ****************************************************************************/ int wolfExample_TLSClient(const char* ip, int port) { int ret = 0; WOLFSSL_CTX* ctx = NULL; WOLFSSL* ssl = NULL; /* create WOLFSSL object */ int sockFd = -1; /* socket file descriptor */ struct sockaddr_in servAddr; /* struct for server address */ char sendBuff[TLS_MAXDATASIZE], rcvBuff[TLS_MAXDATASIZE]; sockFd = socket(AF_INET, SOCK_STREAM, 0); if (sockFd < 0) { printf("Failed to create socket. Error: %d\n", errno); return errno; } memset(&servAddr, 0, sizeof(servAddr)); /* clears memory block for use */ servAddr.sin_family = AF_INET; /* sets addressfamily to internet*/ servAddr.sin_port = htons(port); /* sets port to defined port */ /* looks for the server at the entered address (ip in the command line) */ if (inet_pton(AF_INET, ip, &servAddr.sin_addr) < 1) { /* checks validity of address */ ret = errno; printf("Invalid Address. Error: %d\n", ret); goto exit; } if (connect(sockFd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) { /* if socket fails to connect to the server*/ ret = errno; printf("Connect error. Error: %d\n", ret); goto exit; } /* create and initialize WOLFSSL_CTX structure */ if ((ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())) == NULL) { printf("SSL_CTX_new error.\n"); goto exit; } /* load CA certificates into wolfSSL_CTX. which will verify the server */ ret = wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_der_2048, sizeof_ca_cert_der_2048, SSL_FILETYPE_ASN1); if (ret != SSL_SUCCESS) { printf("Error %d loading CA cert\n", ret); goto exit; } if ((ssl = wolfSSL_new(ctx)) == NULL) { printf("wolfSSL_new error.\n"); goto exit; } wolfSSL_set_fd(ssl, sockFd); ret = wolfSSL_connect(ssl); if (ret == SSL_SUCCESS) { printf("Message for server:\t"); fgets(sendBuff, TLS_MAXDATASIZE, stdin); if (wolfSSL_write(ssl, sendBuff, strlen(sendBuff)) != strlen(sendBuff)) { /* the message is not able to send, or error trying */ ret = wolfSSL_get_error(ssl, 0); printf("Write error: Error: %d\n", ret); goto exit; } memset(rcvBuff, 0, TLS_MAXDATASIZE); if (wolfSSL_read(ssl, rcvBuff, TLS_MAXDATASIZE) < 0) { /* the server failed to send data, or error trying */ ret = wolfSSL_get_error(ssl, 0); printf("Read error. Error: %d\n", ret); goto exit; } printf("Received: \t%s\n", rcvBuff); } exit: /* frees all data before client termination */ if (sockFd != -1) close(sockFd); wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); gServerExit = 1; return ret; } /***************************************************************************** * TLS Server ****************************************************************************/ int wolfExample_TLSServer(int port) { int ret = 0; WOLFSSL_CTX* ctx = NULL; WOLFSSL* ssl = NULL; int sockFd = -1, clientFd = -1; struct sockaddr_in serverAddr = {0}, clientAddr = {0}; const char reply[] = "I hear ya fa shizzle!\n"; int addrSize = sizeof(clientAddr); char buff[256]; sockFd = socket(AF_INET, SOCK_STREAM, 0); if (sockFd < 0) { printf("Failed to create socket. Error: %d\n", errno); return errno; } /* create and initialize WOLFSSL_CTX structure */ if ((ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method())) == NULL) { fprintf(stderr, "wolfSSL_CTX_new error.\n"); goto exit; } /* Load server certificate into WOLFSSL_CTX */ ret = wolfSSL_CTX_use_certificate_buffer(ctx, server_cert_der_2048, sizeof_server_cert_der_2048, SSL_FILETYPE_ASN1); if (ret != SSL_SUCCESS) { fprintf(stderr, "Error %d loading server-cert!\n", ret); goto exit; } /* Load server key into WOLFSSL_CTX */ ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048, sizeof_server_key_der_2048, SSL_FILETYPE_ASN1); if (ret != SSL_SUCCESS) { fprintf(stderr, "Error %d loading server-key!\n", ret); goto exit; } /* Initialize the server address struct to zero */ memset((char *)&serverAddr, 0, sizeof(serverAddr)); /* Fill the server's address family */ serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(port); /* Attach the server socket to our port */ if (bind(sockFd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) { printf("ERROR: failed to bind\n"); goto exit; } printf("Waiting for a connection...\n"); gServerReady = 1; /* Continuously accept connects while not in an active connection */ while (gServerExit == 0) { /* listen for a new connection */ ret = listen(sockFd, SOCK_MAX_PENDING); if (ret == 0) { /* Wait until a client connects */ clientFd = accept(sockFd, (struct sockaddr*)&clientAddr, &addrSize); /* If fails to connect, loop back up and wait for a new connection */ if (clientFd == -1) { printf("failed to accept the connection..\n"); } /* If it connects, read in and reply to the client */ else { printf("Client connected successfully\n"); ssl = wolfSSL_new(ctx); if (ssl == NULL) { fprintf(stderr, "wolfSSL_new error.\n"); break; } /* direct our ssl to our clients connection */ wolfSSL_set_fd(ssl, clientFd); printf("Using Non-Blocking I/O: %d\n", wolfSSL_get_using_nonblock(ssl)); for ( ; ; ) { /* Clear the buffer memory for anything possibly left over */ memset(&buff, 0, sizeof(buff)); /* Read the client data into our buff array */ ret = wolfSSL_read(ssl, buff, sizeof(buff) - 1); if (ret > 0) { /* Print any data the client sends to the console */ printf("Client: %s\n", buff); /* Reply back to the client */ ret = wolfSSL_write(ssl, reply, sizeof(reply) - 1); if (ret < 0) { printf("wolfSSL_write error = %d\n", wolfSSL_get_error(ssl, ret)); gServerExit = 1; break; } } /* if the client disconnects break the loop */ else { if (ret < 0) printf("wolfSSL_read error = %d\n", wolfSSL_get_error(ssl, ret)); else if (ret == 0) printf("The client has closed the connection.\n"); gServerExit = 1; break; } } wolfSSL_free(ssl); /* Free the WOLFSSL object */ ssl = NULL; } close(clientFd); /* close the connected socket */ clientFd = -1; } } /* while */ exit: if (clientFd != -1) close(clientFd); if (sockFd != -1) close(sockFd); wolfSSL_free(ssl); /* Free the WOLFSSL object */ wolfSSL_CTX_free(ctx); /* Free WOLFSSL_CTX */ return ret; } /***************************************************************************** * TLS Local Test ****************************************************************************/ static void wolfSSLLocalServerThread(void* param) { int port = (int)((int*)param); wolfExample_TLSServer(port); } int wolfExample_TLSLocal(int port) { int ret; RTHANDLE srvHandle; /* start server thread */ srvHandle = CreateRtThread(THREAD_BASE_PRIO + 10, (LPPROC)wolfSSLLocalServerThread, WOLF_EXAMPLES_STACK, (void*)port); if (srvHandle == BAD_RTHANDLE) { Fail("Cannot create server thread"); return -1; } /* wait for server to be ready */ while (gServerReady != 1) { RtSleep(0); } /* run client */ ret = wolfExample_TLSClient(TLS_HOST_LOCAL, port); return ret; } /***************************************************************************** * Thread memset(&args, 0, sizeof(args)); ****************************************************************************/ typedef struct func_args { int argc; char** argv; int return_code; } func_args; static void wolfExampleThread(void* param) { func_args args; #ifdef DEBUG_WOLFSSL wolfSSL_Debugging_ON(); #endif /* initialize wolfSSL */ wolfSSL_Init(); while (1) { char rc; gServerExit = 0; gServerReady = 0; printf("\r\n\t\t\t\tMENU\r\n"); printf(menu1); printf("Please select one of the above options: "); rc = getchar(); switch (rc) { case 't': printf("\nCrypt Test\n"); wolfcrypt_test(&args); printf("Crypt Test: Return code %d\n", args.return_code); break; case 'b': printf("\nBenchmark Test\n"); benchmark_test(&args); printf("Benchmark Test: Return code %d\n", args.return_code); break; case 'c': wolfExample_TLSClient(TLS_HOST_REMOTE, TLS_PORT); break; case 's': wolfExample_TLSServer(TLS_PORT); break; case 'l': wolfExample_TLSLocal(TLS_PORT); break; // All other cases go here default: if (rc != '\r' && rc != '\n') printf("\r\nSelection %c out of range\r\n", rc); break; } } wolfSSL_Cleanup(); } /***************************************************************************** * FUNCTION: Catalog * * PARAMETERS: 1. handle of the process whose object directory must be used * 2. the object whose handle must be cataloged * 3. the name to be used (upto 14 characters) * * RETURNS: TRUE on success * * DESCRIPTION: If the given name already exists, * and the existing name refers to a non-existing object, * then the existing name is removed before cataloging. \*****************************************************************************/ BOOLEAN Catalog( RTHANDLE hProcess, RTHANDLE hObject, LPSTR lpszName) { RTHANDLE hOld; if (CatalogRtHandle(hProcess, hObject, lpszName)) return TRUE; // something wrong: check for the case mentioned above if (((hOld = LookupRtHandle(hProcess, lpszName, NO_WAIT)) != BAD_RTHANDLE) && (GetRtHandleType(hOld) == INVALID_TYPE)) { // this is the case mentioned above: remove the old entry and try again if (UncatalogRtHandle(hProcess, lpszName)) return (CatalogRtHandle(hProcess, hObject, lpszName)); } return FALSE; } /***************************************************************************** * FUNCTION: Cleanup (local function) * * DESCRIPTION: * Tell threads to delete themselves and wait a while; * if any thread still exists, kill it. * Remove all other objects as far as they have been created. \*****************************************************************************/ void Cleanup(void) { // indicate that we are cleaning up gInit.state = CLEANUP_BUSY; gInit.bShutdown = TRUE; #ifdef _DEBUG fprintf(stderr, "wolfExamples started cleaning up\n"); #endif // remove our name from the root process if (gInit.bCataloged) { if (!UncatalogRtHandle(hRootProcess, "wolfExample")) Fail("Cannot remove my own name"); } #ifdef _DEBUG fprintf(stderr, "wolfExamples finished cleaning up\n"); #endif // lie down exit(0); } /***************************************************************************** * FUNCTION: Fail * * PARAMETERS: same parameters as expected by printf * * DESCRIPTION: * If in debug mode, prints the message, appending a new line and the error number. * Then the current process is killed graciously: * If the current thread is the main thread, this is done directly. * if the current thread is another one, a terminate request is sent and * the function returns to the calling thread. \*****************************************************************************/ void Fail(LPSTR lpszMessage, ...) { EXCEPTION eh; RTHANDLE hDelMbx; DWORD dwTerminate; #ifdef _DEBUG va_list ap; va_start(ap, lpszMessage); vfprintf(stderr, lpszMessage, ap); va_end(ap); fprintf(stderr, "\nError nr=%x %s\n", GetLastRtError(), GetRtErrorText(GetLastRtError())); #endif // make sure that exceptions are returned for inline handling GetRtExceptionHandlerInfo(THREAD_HANDLER, &eh); eh.ExceptionMode = 0; SetRtExceptionHandler(&eh); // if we had not started initializing yet, just get out if (BEFORE_INIT == gInit.state) exit(0); if (gInit.hMain == GetRtThreadHandles(THIS_THREAD)) { // this is the main thread: // if we are busy initializing, then do Cleanup if (INIT_BUSY == gInit.state) Cleanup(); // does not return // this is the main thread, but we are not initializing: just return return; } // this is not the main thread: // ask main thread to do cleanup // (allow some time to setup the deletion mailbox, ignore errors) hDelMbx = LookupRtHandle(NULL_RTHANDLE, "R?EXIT_MBOX", 5000); dwTerminate = TERMINATE; SendRtData(hDelMbx, &dwTerminate, 4); } /***************************************************************************** * * FUNCTION: UsecsToKticks * * PARAMETERS: 1. number of usecs * * RETURNS: number of low level ticks * * DESCRIPTION: returns the parameter if it is WAIT_FOREVER * otherwise rounds up to number of low level ticks \*****************************************************************************/ DWORD UsecsToKticks(DWORD dwUsecs) { if (dwUsecs == WAIT_FOREVER) return WAIT_FOREVER; return (dwUsecs + dwKtickInUsecs - 1) / dwKtickInUsecs; } /***************************************************************************** * FUNCTION: main * * DESCRIPTION: * This is the main program module. * It creates global objects and all threads. * The main thread then waits for notifications and acts accordingly \*****************************************************************************/ int main(int argc, char* argv[]) { SYSINFO sysinfo; EVENTINFO eiEventInfo; RTHANDLE taskHandle; #ifdef _DEBUG fprintf(stderr, "wolfExamples started\n"); #endif // obtain handle of root process (cannot fail) hRootProcess = GetRtThreadHandles(ROOT_PROCESS); // initialize the structure for cleaning up memset(&gInit, 0, sizeof(gInit)); gInit.state = BEFORE_INIT; // get low level tick length in usecs if (!CopyRtSystemInfo(&sysinfo)) Fail("Cannot copy system info"); dwKtickInUsecs = 10000 / sysinfo.KernelTickRatio; if (dwKtickInUsecs == 0) Fail("Invalid low level tick length"); // adjust process max priority (ignore error) // TODO adjust the 2nd parameter to a value closer to zero if you want to allow more priorities SetRtProcessMaxPriority(NULL_RTHANDLE, THREAD_BASE_PRIO); // obtain main thread's handle gInit.hMain = GetRtThreadHandles(THIS_THREAD); gInit.state = INIT_BUSY; // attempt to catalog the thread but ignore error Catalog(NULL_RTHANDLE, gInit.hMain, "TMain"); // catalog the handle of this process in the root process if (!Catalog(hRootProcess, GetRtThreadHandles(THIS_PROCESS), "wolfExample")) { Fail("Cannot catalog process name"); } gInit.bCataloged = TRUE; // create thread taskHandle = CreateRtThread(THREAD_BASE_PRIO + 20, (LPPROC)wolfExampleThread, WOLF_EXAMPLES_STACK, 0); if (taskHandle == BAD_RTHANDLE) { Fail("Cannot create thread"); } // indicate that initialization has finished gInit.state = INIT_DONE; #ifdef _DEBUG fprintf(stderr, "wolfExamples finished initialization\n"); #endif // wait for notifications while (RtNotifyEvent(RT_SYSTEM_NOTIFICATIONS | RT_EXIT_NOTIFICATIONS, WAIT_FOREVER, &eiEventInfo)) { switch(eiEventInfo.dwNotifyType) { case TERMINATE: // TODO: this process should terminate // cleanup the environment Cleanup(); // does not return case NT_HOST_UP: // TODO: react to a Windows host that has come back break; case NT_BLUESCREEN: // TODO: react to a Windows blue screen break; case KERNEL_STOPPING: // TODO: react to the INtime kernel stopping break; case NT_HOST_HIBERNATE: // TODO: react to the Windows host going in hibernation break; case NT_HOST_STANDBY: // TODO: react to the Windows host going in standby mode break; case NT_HOST_SHUTDOWN_PENDING: // TODO: react to a Windows host that is about to shutdown break; } } Fail("Notify failed"); return 0; }