1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdarg.h>
5 #include <rt.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netdb.h>
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 #include <io.h>
12 
13 #include "wolfExamples.h"
14 #include <wolfssl/wolfcrypt/settings.h>
15 #include <wolfssl/ssl.h>
16 #include <wolfssl/certs_test.h>
17 #include <wolfcrypt/test/test.h>
18 #include <wolfcrypt/benchmark/benchmark.h>
19 
20 
21 /*****************************************************************************
22  * Globals
23  ****************************************************************************/
24 RTHANDLE            hRootProcess;
25 DWORD               dwKtickInUsecs;
26 INIT_STRUCT         gInit;
27 static int gServerExit = 0;
28 static int gServerReady = 0;
29 
30 static const char menu1[] = "\r\n"
31     "\tt. WolfCrypt Test\r\n"
32     "\tb. WolfCrypt Benchmark\r\n"
33     "\tc. WolfSSL Client Example\r\n"
34     "\ts. WolfSSL Server Example\r\n"
35     "\tl. WolfSSL Localhost Client/Server Example\r\n";
36 
37 
38 /*****************************************************************************
39  * Configuration
40  ****************************************************************************/
41 
42 #define TLS_MAXDATASIZE 4096           /* maximum acceptable amount of data */
43 #define TLS_PORT        11111          /* define default port number */
44 #define TLS_HOST_LOCAL  "127.0.0.1"
45 #define TLS_HOST_REMOTE "192.168.0.112"
46 #define SOCK_MAX_PENDING 5
47 #define THREAD_BASE_PRIO 150
48 
49 
50 /*****************************************************************************
51  * TLS Client
52  ****************************************************************************/
wolfExample_TLSClient(const char * ip,int port)53 int wolfExample_TLSClient(const char* ip, int port)
54 {
55     int          ret = 0;
56     WOLFSSL_CTX* ctx = NULL;
57     WOLFSSL*     ssl = NULL;        /* create WOLFSSL object */
58     int                sockFd;      /* socket file descriptor */
59     struct sockaddr_in servAddr;    /* struct for server address */
60     char sendBuff[TLS_MAXDATASIZE], rcvBuff[TLS_MAXDATASIZE];
61 
62     sockFd = socket(AF_INET, SOCK_STREAM, 0);
63     if (sockFd < 0) {
64         printf("Failed to create socket. Error: %d\n", errno);
65         return errno;
66     }
67 
68     memset(&servAddr, 0, sizeof(servAddr)); /* clears memory block for use */
69     servAddr.sin_family = AF_INET;          /* sets addressfamily to internet*/
70     servAddr.sin_port = htons(port);    /* sets port to defined port */
71 
72     /* looks for the server at the entered address (ip in the command line) */
73     if (inet_pton(AF_INET, ip, &servAddr.sin_addr) < 1) {
74         /* checks validity of address */
75         ret = errno;
76         printf("Invalid Address. Error: %d\n", ret);
77         goto exit;
78     }
79 
80     if (connect(sockFd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
81         /* if socket fails to connect to the server*/
82         ret = errno;
83         printf("Connect error. Error: %d\n", ret);
84         goto exit;
85     }
86 
87     /* create and initialize WOLFSSL_CTX structure */
88     if ((ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())) == NULL) {
89         printf("SSL_CTX_new error.\n");
90         goto exit;
91     }
92 
93     /* load CA certificates into wolfSSL_CTX. which will verify the server */
94     ret = wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_der_2048,
95         sizeof_ca_cert_der_2048, SSL_FILETYPE_ASN1);
96     if (ret != SSL_SUCCESS) {
97         printf("Error %d loading CA cert\n", ret);
98         goto exit;
99     }
100     if ((ssl = wolfSSL_new(ctx)) == NULL) {
101         printf("wolfSSL_new error.\n");
102         goto exit;
103     }
104     wolfSSL_set_fd(ssl, sockFd);
105 
106     ret = wolfSSL_connect(ssl);
107     if (ret == SSL_SUCCESS) {
108         printf("Message for server:\t");
109         fgets(sendBuff, TLS_MAXDATASIZE, stdin);
110 
111         if (wolfSSL_write(ssl, sendBuff, strlen(sendBuff)) != strlen(sendBuff)) {
112             /* the message is not able to send, or error trying */
113             ret = wolfSSL_get_error(ssl, 0);
114             printf("Write error: Error: %d\n", ret);
115             goto exit;
116         }
117 
118         memset(rcvBuff, 0, TLS_MAXDATASIZE);
119         if (wolfSSL_read(ssl, rcvBuff, TLS_MAXDATASIZE) < 0) {
120             /* the server failed to send data, or error trying */
121             ret = wolfSSL_get_error(ssl, 0);
122             printf("Read error. Error: %d\n", ret);
123             goto exit;
124         }
125         printf("Received: \t%s\n", rcvBuff);
126     }
127 
128 exit:
129     /* frees all data before client termination */
130     if (sockFd != -1)
131         close(sockFd);
132     wolfSSL_free(ssl);
133     wolfSSL_CTX_free(ctx);
134     gServerExit = 1;
135 
136     return ret;
137 }
138 
139 /*****************************************************************************
140  * TLS Server
141  ****************************************************************************/
wolfExample_TLSServer(int port)142 int wolfExample_TLSServer(int port)
143 {
144     int ret = 0;
145     WOLFSSL_CTX* ctx = NULL;
146     WOLFSSL* ssl = NULL;
147     int sockFd, clientFd = -1;
148     struct sockaddr_in serverAddr = {0}, clientAddr = {0};
149     const char reply[]  = "I hear ya fa shizzle!\n";
150     int addrSize        = sizeof(clientAddr);
151     char buff[256];
152 
153     sockFd = socket(AF_INET, SOCK_STREAM, 0);
154     if (sockFd < 0) {
155         printf("Failed to create socket. Error: %d\n", errno);
156         return errno;
157     }
158 
159     /* create and initialize WOLFSSL_CTX structure */
160     if ((ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method())) == NULL) {
161         fprintf(stderr, "wolfSSL_CTX_new error.\n");
162         goto exit;
163     }
164 
165     /* Load server certificate into WOLFSSL_CTX */
166     ret = wolfSSL_CTX_use_certificate_buffer(ctx, server_cert_der_2048,
167         sizeof_server_cert_der_2048, SSL_FILETYPE_ASN1);
168     if (ret != SSL_SUCCESS) {
169         fprintf(stderr, "Error %d loading server-cert!\n", ret);
170         goto exit;
171     }
172 
173     /* Load server key into WOLFSSL_CTX */
174     ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
175         sizeof_server_key_der_2048, SSL_FILETYPE_ASN1);
176     if (ret != SSL_SUCCESS) {
177         fprintf(stderr, "Error %d loading server-key!\n", ret);
178         goto exit;
179     }
180 
181     /* Initialize the server address struct to zero */
182     memset((char *)&serverAddr, 0, sizeof(serverAddr));
183 
184     /* Fill the server's address family */
185     serverAddr.sin_family      = AF_INET;
186     serverAddr.sin_addr.s_addr = INADDR_ANY;
187     serverAddr.sin_port        = htons(port);
188 
189     /* Attach the server socket to our port */
190     if (bind(sockFd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
191         printf("ERROR: failed to bind\n");
192         goto exit;
193     }
194 
195     printf("Waiting for a connection...\n");
196     gServerReady = 1;
197 
198     /* Continuously accept connects while not in an active connection */
199     while (gServerExit == 0) {
200         /* listen for a new connection */
201         ret = listen(sockFd, SOCK_MAX_PENDING);
202         if (ret == 0) {
203             /* Wait until a client connects */
204             clientFd = accept(sockFd, (struct sockaddr*)&clientAddr, &addrSize);
205 
206             /* If fails to connect, loop back up and wait for a new connection */
207             if (clientFd == -1) {
208                 printf("failed to accept the connection..\n");
209             }
210             /* If it connects, read in and reply to the client */
211             else {
212                 printf("Client connected successfully\n");
213 
214                 ssl = wolfSSL_new(ctx);
215                 if (ssl == NULL) {
216                     fprintf(stderr, "wolfSSL_new error.\n");
217                     break;
218                 }
219 
220                 /* direct our ssl to our clients connection */
221                 wolfSSL_set_fd(ssl, clientFd);
222 
223                 printf("Using Non-Blocking I/O: %d\n",
224                     wolfSSL_get_using_nonblock(ssl));
225 
226                 for ( ; ; ) {
227                     /* Clear the buffer memory for anything  possibly left over */
228                     memset(&buff, 0, sizeof(buff));
229 
230                     /* Read the client data into our buff array */
231 					ret = wolfSSL_read(ssl, buff, sizeof(buff) - 1);
232                     if (ret > 0) {
233                         /* Print any data the client sends to the console */
234                         printf("Client: %s\n", buff);
235 
236                         /* Reply back to the client */
237 						ret = wolfSSL_write(ssl, reply, sizeof(reply) - 1);
238                         if (ret < 0) {
239                             printf("wolfSSL_write error = %d\n",
240                                 wolfSSL_get_error(ssl, ret));
241                             gServerExit = 1;
242                             break;
243                         }
244                     }
245                     /* if the client disconnects break the loop */
246                     else {
247                         if (ret < 0)
248                             printf("wolfSSL_read error = %d\n",
249                                 wolfSSL_get_error(ssl, ret));
250                         else if (ret == 0)
251                             printf("The client has closed the connection.\n");
252                         gServerExit = 1;
253                         break;
254                     }
255                 }
256                 wolfSSL_free(ssl);           /* Free the WOLFSSL object */
257                 ssl = NULL;
258             }
259             close(clientFd);               /* close the connected socket */
260             clientFd = -1;
261         }
262     } /* while */
263 
264 exit:
265     if (clientFd != -1)
266         close(clientFd);
267     if (sockFd != -1)
268         close(sockFd);
269     wolfSSL_free(ssl);       /* Free the WOLFSSL object */
270     wolfSSL_CTX_free(ctx);   /* Free WOLFSSL_CTX */
271 
272     return ret;
273 }
274 
275 /*****************************************************************************
276  * TLS Local Test
277  ****************************************************************************/
wolfSSLLocalServerThread(void * param)278 static void wolfSSLLocalServerThread(void* param)
279 {
280     int port = (int)((int*)param);
281     wolfExample_TLSServer(port);
282 }
283 
wolfExample_TLSLocal(int port)284 int wolfExample_TLSLocal(int port)
285 {
286     int ret;
287     RTHANDLE srvHandle;
288 
289     /* start server thread */
290     srvHandle = CreateRtThread(THREAD_BASE_PRIO + 10,
291         (LPPROC)wolfSSLLocalServerThread, WOLF_EXAMPLES_STACK, (void*)port);
292     if (srvHandle == BAD_RTHANDLE) {
293         Fail("Cannot create server thread");
294         return -1;
295     }
296 
297     /* wait for server to be ready */
298     while (gServerReady != 1) {
299         RtSleep(0);
300     }
301 
302     /* run client */
303     ret = wolfExample_TLSClient(TLS_HOST_LOCAL, port);
304 
305     return ret;
306 }
307 
308 
309 /*****************************************************************************
310  * Thread
311         memset(&args, 0, sizeof(args));
312  ****************************************************************************/
313 typedef struct func_args {
314     int    argc;
315     char** argv;
316     int    return_code;
317 } func_args;
318 
wolfExampleThread(void * param)319 static void wolfExampleThread(void* param)
320 {
321     func_args args;
322 
323 #ifdef DEBUG_WOLFSSL
324     wolfSSL_Debugging_ON();
325 #endif
326 
327     /* initialize wolfSSL */
328     wolfSSL_Init();
329 
330     while (1) {
331         char rc;
332 
333         gServerExit = 0;
334         gServerReady = 0;
335 
336         printf("\r\n\t\t\t\tMENU\r\n");
337         printf(menu1);
338         printf("Please select one of the above options: ");
339 
340         rc = getchar();
341         switch (rc) {
342             case 't':
343                 printf("\nCrypt Test\n");
344                 wolfcrypt_test(&args);
345                 printf("Crypt Test: Return code %d\n", args.return_code);
346                 break;
347 
348             case 'b':
349                 printf("\nBenchmark Test\n");
350                 benchmark_test(&args);
351                 printf("Benchmark Test: Return code %d\n", args.return_code);
352                 break;
353 
354             case 'c':
355                 wolfExample_TLSClient(TLS_HOST_REMOTE, TLS_PORT);
356                 break;
357 
358             case 's':
359                 wolfExample_TLSServer(TLS_PORT);
360                 break;
361 
362             case 'l':
363                 wolfExample_TLSLocal(TLS_PORT);
364                 break;
365 
366             // All other cases go here
367             default:
368                 if (rc != '\r' && rc != '\n')
369                     printf("\r\nSelection %c out of range\r\n", rc);
370                 break;
371         }
372     }
373 
374     wolfSSL_Cleanup();
375 }
376 
377 
378 /*****************************************************************************
379 * FUNCTION:		Catalog
380 *
381 * PARAMETERS:	1. handle of the process whose object directory must be used
382 *				2. the object whose handle must be cataloged
383 *				3. the name to be used (upto 14 characters)
384 *
385 * RETURNS:		TRUE on success
386 *
387 * DESCRIPTION:	If the given name already exists,
388 *				and the existing name refers to a non-existing object,
389 *				then the existing name is removed before cataloging.
390 \*****************************************************************************/
Catalog(RTHANDLE hProcess,RTHANDLE hObject,LPSTR lpszName)391 BOOLEAN Catalog(
392 	RTHANDLE			hProcess,
393 	RTHANDLE			hObject,
394 	LPSTR				lpszName)
395 {
396 	RTHANDLE		hOld;
397 
398 	if (CatalogRtHandle(hProcess, hObject, lpszName))
399 		return TRUE;
400 
401 	// something wrong: check for the case mentioned above
402 	if (((hOld = LookupRtHandle(hProcess, lpszName, NO_WAIT)) != BAD_RTHANDLE) &&
403 		(GetRtHandleType(hOld) == INVALID_TYPE))
404 	{
405 		// this is the case mentioned above: remove the old entry and try again
406 		if (UncatalogRtHandle(hProcess, lpszName))
407 			return (CatalogRtHandle(hProcess, hObject, lpszName));
408 	}
409 	return FALSE;
410 }
411 
412 /*****************************************************************************
413 * FUNCTION:   Cleanup (local function)
414 *
415 * DESCRIPTION:
416 *  Tell threads to delete themselves and wait a while;
417 *  if any thread still exists, kill it.
418 *  Remove all other objects as far as they have been created.
419 \*****************************************************************************/
Cleanup(void)420 void Cleanup(void)
421 {
422 	// indicate that we are cleaning up
423 	gInit.state		= CLEANUP_BUSY;
424 	gInit.bShutdown = TRUE;
425 
426 #ifdef _DEBUG
427   fprintf(stderr, "wolfExamples started cleaning up\n");
428 #endif
429 
430 	// remove our name from the root process
431 	if (gInit.bCataloged) {
432 		if (!UncatalogRtHandle(hRootProcess, "wolfExample"))
433 			Fail("Cannot remove my own name");
434     }
435 
436 #ifdef _DEBUG
437 	fprintf(stderr, "wolfExamples finished cleaning up\n");
438 #endif
439 
440 	// lie down
441 	exit(0);
442 }
443 
444 /*****************************************************************************
445 * FUNCTION:     	Fail
446 *
447 * PARAMETERS:   	same parameters as expected by printf
448 *
449 * DESCRIPTION:
450 *  If in debug mode, prints the message, appending a new line and the error number.
451 *  Then the current process is killed graciously:
452 *  If the current thread is the main thread, this is done directly.
453 *  if the current thread is another one, a terminate request is sent and
454 *  the function returns to the calling thread.
455 \*****************************************************************************/
Fail(LPSTR lpszMessage,...)456 void Fail(LPSTR lpszMessage, ...)
457 {
458 	EXCEPTION		eh;
459 	RTHANDLE		hDelMbx;
460 	DWORD			dwTerminate;
461 
462 #ifdef _DEBUG
463 	va_list			ap;
464 
465 	va_start(ap, lpszMessage);
466 	vfprintf(stderr, lpszMessage, ap);
467 	va_end(ap);
468 	fprintf(stderr, "\nError nr=%x %s\n", GetLastRtError(), GetRtErrorText(GetLastRtError()));
469 #endif
470 
471 	// make sure that exceptions are returned for inline handling
472 	GetRtExceptionHandlerInfo(THREAD_HANDLER, &eh);
473 	eh.ExceptionMode = 0;
474 	SetRtExceptionHandler(&eh);
475 
476 	// if we had not started initializing yet, just get out
477 	if (BEFORE_INIT == gInit.state)
478 		exit(0);
479 
480 	if (gInit.hMain == GetRtThreadHandles(THIS_THREAD))
481 	{
482 		// this is the main thread:
483 		// if we are busy initializing, then do Cleanup
484 		if (INIT_BUSY == gInit.state)
485 			Cleanup();  // does not return
486 
487 		// this is the main thread, but we are not initializing: just return
488 		return;
489 	}
490 
491 	// this is not the main thread:
492 	// ask main thread to do cleanup
493 	// (allow some time to setup the deletion mailbox, ignore errors)
494 	hDelMbx			= LookupRtHandle(NULL_RTHANDLE, "R?EXIT_MBOX", 5000);
495 	dwTerminate		= TERMINATE;
496 	SendRtData(hDelMbx, &dwTerminate, 4);
497 }
498 
499 /*****************************************************************************
500 *
501 * FUNCTION:		UsecsToKticks
502 *
503 * PARAMETERS:	1. number of usecs
504 *
505 * RETURNS:		number of low level ticks
506 *
507 * DESCRIPTION:	returns the parameter if it is WAIT_FOREVER
508 *				otherwise rounds up to number of low level ticks
509 \*****************************************************************************/
UsecsToKticks(DWORD dwUsecs)510 DWORD UsecsToKticks(DWORD dwUsecs)
511 {
512 	if (dwUsecs == WAIT_FOREVER)
513 		return WAIT_FOREVER;
514 
515 	return (dwUsecs + dwKtickInUsecs - 1) / dwKtickInUsecs;
516 }
517 
518 
519 /*****************************************************************************
520 * FUNCTION:         main
521 *
522 * DESCRIPTION:
523 *  This is the main program module.
524 *  It creates global objects  and all threads.
525 *  The main thread then waits for notifications and acts accordingly
526 \*****************************************************************************/
main(int argc,char * argv[])527 int main(int argc, char* argv[])
528 {
529     SYSINFO         sysinfo;
530     EVENTINFO       eiEventInfo;
531     RTHANDLE        taskHandle;
532 
533 #ifdef _DEBUG
534     fprintf(stderr, "wolfExamples started\n");
535 #endif
536 
537     // obtain handle of root process (cannot fail)
538     hRootProcess    = GetRtThreadHandles(ROOT_PROCESS);
539 
540     // initialize the structure for cleaning up
541     memset(&gInit, 0, sizeof(gInit));
542     gInit.state     = BEFORE_INIT;
543 
544     // get low level tick length in usecs
545     if (!CopyRtSystemInfo(&sysinfo))
546         Fail("Cannot copy system info");
547     dwKtickInUsecs  = 10000 / sysinfo.KernelTickRatio;
548     if (dwKtickInUsecs == 0)
549         Fail("Invalid low level tick length");
550 
551     // adjust process max priority (ignore error)
552     // TODO adjust the 2nd parameter to a value closer to zero if you want to allow more priorities
553     SetRtProcessMaxPriority(NULL_RTHANDLE, THREAD_BASE_PRIO);
554 
555     // obtain main thread's handle
556     gInit.hMain     = GetRtThreadHandles(THIS_THREAD);
557     gInit.state     = INIT_BUSY;
558 
559     // attempt to catalog the thread but ignore error
560     Catalog(NULL_RTHANDLE, gInit.hMain, "TMain");
561 
562     // catalog the handle of this process in the root process
563     if (!Catalog(hRootProcess, GetRtThreadHandles(THIS_PROCESS), "wolfExample")) {
564         Fail("Cannot catalog process name");
565     }
566     gInit.bCataloged = TRUE;
567 
568     // create thread
569     taskHandle = CreateRtThread(THREAD_BASE_PRIO + 20,
570         (LPPROC)wolfExampleThread, WOLF_EXAMPLES_STACK, 0);
571     if (taskHandle == BAD_RTHANDLE) {
572         Fail("Cannot create thread");
573     }
574 
575     // indicate that initialization has finished
576     gInit.state     = INIT_DONE;
577 #ifdef _DEBUG
578     fprintf(stderr, "wolfExamples finished initialization\n");
579 #endif
580 
581     // wait for notifications
582     while (RtNotifyEvent(RT_SYSTEM_NOTIFICATIONS | RT_EXIT_NOTIFICATIONS,
583         WAIT_FOREVER, &eiEventInfo))
584     {
585         switch(eiEventInfo.dwNotifyType)
586         {
587         case TERMINATE:
588             // TODO: this process should terminate
589             // cleanup the environment
590             Cleanup();  // does not return
591 
592         case NT_HOST_UP:
593             // TODO: react to a Windows host that has come back
594             break;
595 
596         case NT_BLUESCREEN:
597             // TODO: react to a Windows blue screen
598             break;
599 
600         case KERNEL_STOPPING:
601             // TODO: react to the INtime kernel stopping
602             break;
603 
604         case NT_HOST_HIBERNATE:
605             // TODO: react to the Windows host going in hibernation
606             break;
607 
608         case NT_HOST_STANDBY:
609             // TODO: react to the Windows host going in standby mode
610             break;
611 
612         case NT_HOST_SHUTDOWN_PENDING:
613             // TODO: react to a Windows host that is about to shutdown
614             break;
615         }
616     }
617     Fail("Notify failed");
618     return 0;
619 }
620