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