1 /* echoserver.c
2  *
3  * Copyright (C) 2006-2021 wolfSSL Inc.
4  *
5  * This file is part of wolfSSL.
6  *
7  * wolfSSL is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * wolfSSL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20  */
21 
22 
23 #ifdef HAVE_CONFIG_H
24     #include <config.h>
25 #endif
26 
27 #include <cyassl/ssl.h> /* name change portability layer */
28 #include <cyassl/ctaocrypt/settings.h>
29 #ifdef HAVE_ECC
30     #include <cyassl/ctaocrypt/ecc.h>   /* ecc_fp_free */
31 #endif
32 
33 #if defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET)
34         #include <stdio.h>
35         #include <string.h>
36         #include "cmsis_os.h"
37         #include "rl_fs.h"
38         #include "rl_net.h"
39         #include "wolfssl_MDK_ARM.h"
40 #endif
41 
42 #include <cyassl/ssl.h>
43 #include <cyassl/test.h>
44 
45 #ifndef NO_MAIN_DRIVER
46     #define ECHO_OUT
47 #endif
48 
49 #include "examples/echoserver/echoserver.h"
50 
51 #ifndef NO_WOLFSSL_SERVER
52 
53 #ifdef NO_FILESYSTEM
54 #ifdef NO_RSA
55 #error currently the example only tries to load in a RSA buffer
56 #endif
57 #undef USE_CERT_BUFFERS_2048
58 #define USE_CERT_BUFFERS_2048
59 #include <wolfssl/certs_test.h>
60 #endif
61 
62 #ifdef WOLFSSL_ASYNC_CRYPT
63     static int devId = INVALID_DEVID;
64 #endif
65 
66 #define SVR_COMMAND_SIZE 256
67 
SignalReady(void * args,word16 port)68 static void SignalReady(void* args, word16 port)
69 {
70 #if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && !defined(__MINGW32__)
71     /* signal ready to tcp_accept */
72     func_args* server_args = (func_args*)args;
73     tcp_ready* ready = server_args->signal;
74     pthread_mutex_lock(&ready->mutex);
75     ready->ready = 1;
76     ready->port = port;
77     pthread_cond_signal(&ready->cond);
78     pthread_mutex_unlock(&ready->mutex);
79 #endif
80     (void)args;
81     (void)port;
82 }
83 
84 
echoserver_test(void * args)85 THREAD_RETURN CYASSL_THREAD echoserver_test(void* args)
86 {
87     SOCKET_T       sockfd = 0;
88     CYASSL_METHOD* method = 0;
89     CYASSL_CTX*    ctx    = 0;
90 
91     int    ret = 0;
92     int    doDTLS = 0;
93     int    doPSK;
94     int    outCreated = 0;
95     int    shutDown = 0;
96     int    useAnyAddr = 0;
97     word16 port;
98     int    argc = ((func_args*)args)->argc;
99     char** argv = ((func_args*)args)->argv;
100     char   buffer[CYASSL_MAX_ERROR_SZ];
101 
102 #ifdef ECHO_OUT
103     FILE* fout = stdout;
104     if (argc >= 2) {
105         fout = fopen(argv[1], "w");
106         outCreated = 1;
107     }
108     if (!fout) err_sys("can't open output file");
109 #endif
110     (void)outCreated;
111     (void)argc;
112     (void)argv;
113 
114     ((func_args*)args)->return_code = -1; /* error state */
115 
116 #ifdef CYASSL_DTLS
117     doDTLS  = 1;
118 #endif
119 
120 #if (defined(NO_RSA) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \
121                                 !defined(HAVE_ED448)) || defined(CYASSL_LEANPSK)
122     doPSK = 1;
123 #else
124     doPSK = 0;
125 #endif
126 
127 #if defined(NO_MAIN_DRIVER) && !defined(CYASSL_SNIFFER) && \
128      !defined(WOLFSSL_MDK_SHELL) && !defined(CYASSL_TIRTOS) && \
129      !defined(USE_WINDOWS_API)
130     /* Let tcp_listen assign port */
131     port = 0;
132 #else
133     /* Use default port */
134     port = wolfSSLPort;
135 #endif
136 
137 #if defined(USE_ANY_ADDR)
138     useAnyAddr = 1;
139 #endif
140 
141 #ifdef CYASSL_TIRTOS
142     fdOpenSession(Task_self());
143 #endif
144 
145     tcp_listen(&sockfd, &port, useAnyAddr, doDTLS, 0);
146 
147 #if defined(CYASSL_DTLS)
148     method  = CyaDTLSv1_2_server_method();
149 #elif !defined(NO_TLS)
150     #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_SNIFFER)
151     method = CyaTLSv1_2_server_method();
152     #else
153     method = CyaSSLv23_server_method();
154     #endif
155 #elif defined(WOLFSSL_ALLOW_SSLV3)
156     method = CyaSSLv3_server_method();
157 #else
158     #error "no valid server method built in"
159 #endif
160     ctx    = CyaSSL_CTX_new(method);
161     /* CyaSSL_CTX_set_session_cache_mode(ctx, WOLFSSL_SESS_CACHE_OFF); */
162 
163 #ifdef WOLFSSL_ENCRYPTED_KEYS
164     CyaSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
165 #endif
166 
167 #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
168     ((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
169     if (TicketInit() != 0)
170         err_sys("unable to setup Session Ticket Key context");
171     wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb);
172 #endif
173 
174 #ifndef NO_FILESYSTEM
175     if (doPSK == 0) {
176     #if defined(HAVE_ECC) && !defined(CYASSL_SNIFFER)
177         /* ecc */
178         if (CyaSSL_CTX_use_certificate_file(ctx, eccCertFile, WOLFSSL_FILETYPE_PEM)
179                 != WOLFSSL_SUCCESS)
180             err_sys("can't load server cert file, "
181                     "Please run from wolfSSL home dir");
182 
183         if (CyaSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile, WOLFSSL_FILETYPE_PEM)
184                 != WOLFSSL_SUCCESS)
185             err_sys("can't load server key file, "
186                     "Please run from wolfSSL home dir");
187     #elif defined(HAVE_ED25519) && !defined(CYASSL_SNIFFER)
188         /* ed25519 */
189         if (CyaSSL_CTX_use_certificate_chain_file(ctx, edCertFile)
190                 != WOLFSSL_SUCCESS)
191             err_sys("can't load server cert file, "
192                     "Please run from wolfSSL home dir");
193 
194         if (CyaSSL_CTX_use_PrivateKey_file(ctx, edKeyFile, WOLFSSL_FILETYPE_PEM)
195                 != WOLFSSL_SUCCESS)
196             err_sys("can't load server key file, "
197                     "Please run from wolfSSL home dir");
198     #elif defined(HAVE_ED448) && !defined(CYASSL_SNIFFER)
199         /* ed448 */
200         if (CyaSSL_CTX_use_certificate_chain_file(ctx, ed448CertFile)
201                 != WOLFSSL_SUCCESS)
202             err_sys("can't load server cert file, "
203                     "Please run from wolfSSL home dir");
204 
205         if (CyaSSL_CTX_use_PrivateKey_file(ctx, ed448KeyFile,
206                 WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS)
207             err_sys("can't load server key file, "
208                     "Please run from wolfSSL home dir");
209     #elif defined(NO_CERTS)
210         /* do nothing, just don't load cert files */
211     #else
212         /* normal */
213         if (CyaSSL_CTX_use_certificate_file(ctx, svrCertFile, WOLFSSL_FILETYPE_PEM)
214                 != WOLFSSL_SUCCESS)
215             err_sys("can't load server cert file, "
216                     "Please run from wolfSSL home dir");
217 
218         if (CyaSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, WOLFSSL_FILETYPE_PEM)
219                 != WOLFSSL_SUCCESS)
220             err_sys("can't load server key file, "
221                     "Please run from wolfSSL home dir");
222     #endif
223     } /* doPSK */
224 #elif !defined(NO_CERTS)
225     if (!doPSK) {
226         if (CyaSSL_CTX_use_certificate_buffer(ctx, server_cert_der_2048,
227             sizeof_server_cert_der_2048, WOLFSSL_FILETYPE_ASN1)
228             != WOLFSSL_SUCCESS)
229             err_sys("can't load server cert buffer");
230 
231         if (CyaSSL_CTX_use_PrivateKey_buffer(ctx, server_key_der_2048,
232             sizeof_server_key_der_2048, WOLFSSL_FILETYPE_ASN1)
233             != WOLFSSL_SUCCESS)
234             err_sys("can't load server key buffer");
235     }
236 #endif
237 
238 #if defined(CYASSL_SNIFFER)
239     /* Only set if not running testsuite */
240     if (XSTRSTR(argv[0], "testsuite") != 0) {
241         /* don't use EDH, can't sniff tmp keys */
242         CyaSSL_CTX_set_cipher_list(ctx, "AES256-SHA");
243     }
244 #endif
245 
246     if (doPSK) {
247 #ifndef NO_PSK
248         const char *defaultCipherList;
249 
250         CyaSSL_CTX_set_psk_server_callback(ctx, my_psk_server_cb);
251         CyaSSL_CTX_use_psk_identity_hint(ctx, "cyassl server");
252         #ifdef HAVE_NULL_CIPHER
253             defaultCipherList = "PSK-NULL-SHA256";
254         #elif defined(HAVE_AESGCM) && !defined(NO_DH)
255             #ifdef WOLFSSL_TLS13
256             defaultCipherList = "TLS13-AES128-GCM-SHA256"
257                 #ifndef WOLFSSL_NO_TLS12
258                                 ":DHE-PSK-AES128-GCM-SHA256"
259                 #endif
260                 ;
261             #else
262             defaultCipherList = "DHE-PSK-AES128-GCM-SHA256";
263             #endif
264         #elif defined(HAVE_AESGCM) && defined(WOLFSSL_TLS13)
265             defaultCipherList = "TLS13-AES128-GCM-SHA256"
266                 #ifndef WOLFSSL_NO_TLS12
267                                 ":PSK-AES128-GCM-SHA256"
268                 #endif
269                 ;
270         #else
271             defaultCipherList = "PSK-AES128-CBC-SHA256";
272         #endif
273         if (CyaSSL_CTX_set_cipher_list(ctx, defaultCipherList) != WOLFSSL_SUCCESS)
274             err_sys("server can't set cipher list 2");
275         wolfSSL_CTX_set_psk_callback_ctx(ctx, (void*)defaultCipherList);
276 #endif
277     }
278 
279 #ifdef WOLFSSL_ASYNC_CRYPT
280     ret = wolfAsync_DevOpen(&devId);
281     if (ret < 0) {
282         printf("Async device open failed\nRunning without async\n");
283     }
284     wolfSSL_CTX_SetDevId(ctx, devId);
285 #endif /* WOLFSSL_ASYNC_CRYPT */
286 
287     SignalReady(args, port);
288 
289     while (!shutDown) {
290         CYASSL* ssl = NULL;
291         CYASSL* write_ssl = NULL;   /* may have separate w/ HAVE_WRITE_DUP */
292         char    command[SVR_COMMAND_SIZE+1];
293         int     echoSz = 0;
294         int     clientfd;
295         int     firstRead = 1;
296         int     gotFirstG = 0;
297         int     err = 0;
298         SOCKADDR_IN_T client;
299         socklen_t     client_len = sizeof(client);
300 #ifndef CYASSL_DTLS
301         clientfd = accept(sockfd, (struct sockaddr*)&client,
302                          (ACCEPT_THIRD_T)&client_len);
303 #else
304         clientfd = sockfd;
305         {
306             /* For DTLS, peek at the next datagram so we can get the client's
307              * address and set it into the ssl object later to generate the
308              * cookie. */
309             int n;
310             byte b[1500];
311             n = (int)recvfrom(clientfd, (char*)b, sizeof(b), MSG_PEEK,
312                               (struct sockaddr*)&client, &client_len);
313             if (n <= 0)
314                 err_sys("recvfrom failed");
315         }
316 #endif
317         if (WOLFSSL_SOCKET_IS_INVALID(clientfd)) err_sys("tcp accept failed");
318 
319         ssl = CyaSSL_new(ctx);
320         if (ssl == NULL) err_sys("SSL_new failed");
321         CyaSSL_set_fd(ssl, clientfd);
322         #ifdef CYASSL_DTLS
323             wolfSSL_dtls_set_peer(ssl, &client, client_len);
324         #endif
325         #if !defined(NO_FILESYSTEM) && !defined(NO_DH) && !defined(NO_ASN)
326             CyaSSL_SetTmpDH_file(ssl, dhParamFile, WOLFSSL_FILETYPE_PEM);
327         #elif !defined(NO_DH)
328             SetDH(ssl);  /* will repick suites with DHE, higher than PSK */
329         #endif
330 
331         do {
332             err = 0; /* Reset error */
333             ret = CyaSSL_accept(ssl);
334             if (ret != WOLFSSL_SUCCESS) {
335                 err = CyaSSL_get_error(ssl, 0);
336             #ifdef WOLFSSL_ASYNC_CRYPT
337                 if (err == WC_PENDING_E) {
338                     ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
339                     if (ret < 0) break;
340                 }
341             #endif
342             }
343         } while (err == WC_PENDING_E);
344         if (ret != WOLFSSL_SUCCESS) {
345             printf("SSL_accept error = %d, %s\n", err,
346                 CyaSSL_ERR_error_string(err, buffer));
347             printf("SSL_accept failed\n");
348             CyaSSL_free(ssl);
349             CloseSocket(clientfd);
350             continue;
351         }
352 #if defined(PEER_INFO)
353         showPeer(ssl);
354 #endif
355 
356 #ifdef HAVE_WRITE_DUP
357         write_ssl = wolfSSL_write_dup(ssl);
358         if (write_ssl == NULL) {
359             printf("wolfSSL_write_dup failed\n");
360             CyaSSL_free(ssl);
361             CloseSocket(clientfd);
362             continue;
363         }
364 #else
365         write_ssl = ssl;
366 #endif
367 
368         while (1) {
369             do {
370                 err = 0; /* reset error */
371                 ret = CyaSSL_read(ssl, command, sizeof(command)-1);
372                 if (ret <= 0) {
373                     err = CyaSSL_get_error(ssl, 0);
374                 #ifdef WOLFSSL_ASYNC_CRYPT
375                     if (err == WC_PENDING_E) {
376                         ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
377                         if (ret < 0) break;
378                     }
379                 #endif
380                 }
381             } while (err == WC_PENDING_E);
382             if (ret <= 0) {
383                 if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_ZERO_RETURN){
384                     printf("SSL_read echo error %d, %s!\n", err,
385                         CyaSSL_ERR_error_string(err, buffer));
386                 }
387                 break;
388             }
389 
390             echoSz = ret;
391 
392             if (firstRead == 1) {
393                 firstRead = 0;  /* browser may send 1 byte 'G' to start */
394                 if (echoSz == 1 && command[0] == 'G') {
395                     gotFirstG = 1;
396                     continue;
397                 }
398             }
399             else if (gotFirstG == 1 && strncmp(command, "ET /", 4) == 0) {
400                 strncpy(command, "GET", 4);
401                 /* fall through to normal GET */
402             }
403 
404             if ( strncmp(command, "quit", 4) == 0) {
405                 printf("client sent quit command: shutting down!\n");
406                 shutDown = 1;
407                 break;
408             }
409             if ( strncmp(command, "break", 5) == 0) {
410                 printf("client sent break command: closing session!\n");
411                 break;
412             }
413 #ifdef PRINT_SESSION_STATS
414             if ( strncmp(command, "printstats", 10) == 0) {
415                 CyaSSL_PrintSessionStats();
416                 break;
417             }
418 #endif
419             if (strncmp(command, "GET", 3) == 0) {
420                 const char resp[] =
421                     "HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n"
422                     "<html><body BGCOLOR=\"#ffffff\"><pre>\r\n"
423                     "greetings from wolfSSL\r\n</pre></body></html>\r\n\r\n";
424 
425                 echoSz = (int)strlen(resp) + 1;
426                 if (echoSz > (int)sizeof(command)) {
427                     /* Internal error. */
428                     err_sys("HTTP response greater than buffer.");
429                 }
430                 strncpy(command, resp, sizeof(command));
431 
432                 do {
433                     err = 0; /* reset error */
434                     ret = CyaSSL_write(write_ssl, command, echoSz);
435                     if (ret <= 0) {
436                         err = CyaSSL_get_error(write_ssl, 0);
437                     #ifdef WOLFSSL_ASYNC_CRYPT
438                         if (err == WC_PENDING_E) {
439                             ret = wolfSSL_AsyncPoll(write_ssl, WOLF_POLL_FLAG_CHECK_HW);
440                             if (ret < 0) break;
441                         }
442                     #endif
443                     }
444                 } while (err == WC_PENDING_E);
445                 if (ret != echoSz) {
446                     printf("SSL_write get error = %d, %s\n", err,
447                         CyaSSL_ERR_error_string(err, buffer));
448                     err_sys("SSL_write get failed");
449                 }
450                 break;
451             }
452             command[echoSz] = 0;
453 
454         #ifdef ECHO_OUT
455             fputs(command, fout);
456         #endif
457 
458             do {
459                 err = 0; /* reset error */
460                 ret = CyaSSL_write(write_ssl, command, echoSz);
461                 if (ret <= 0) {
462                     err = CyaSSL_get_error(write_ssl, 0);
463                 #ifdef WOLFSSL_ASYNC_CRYPT
464                     if (err == WC_PENDING_E) {
465                         ret = wolfSSL_AsyncPoll(write_ssl, WOLF_POLL_FLAG_CHECK_HW);
466                         if (ret < 0) break;
467                     }
468                 #endif
469                 }
470             } while (err == WC_PENDING_E);
471 
472             if (ret != echoSz) {
473                 printf("SSL_write echo error = %d, %s\n", err,
474                         CyaSSL_ERR_error_string(err, buffer));
475                 err_sys("SSL_write echo failed");
476             }
477         }
478 #ifndef CYASSL_DTLS
479         CyaSSL_shutdown(ssl);
480 #endif
481 #ifdef HAVE_WRITE_DUP
482         CyaSSL_free(write_ssl);
483 #endif
484         CyaSSL_free(ssl);
485         CloseSocket(clientfd);
486 #ifdef CYASSL_DTLS
487         tcp_listen(&sockfd, &port, useAnyAddr, doDTLS, 0);
488         SignalReady(args, port);
489 #endif
490     }
491 
492     CloseSocket(sockfd);
493     CyaSSL_CTX_free(ctx);
494 
495 #ifdef ECHO_OUT
496     if (outCreated)
497         fclose(fout);
498 #endif
499 
500     ((func_args*)args)->return_code = 0;
501 
502 #if defined(NO_MAIN_DRIVER) && defined(HAVE_ECC) && defined(FP_ECC) \
503                             && defined(HAVE_THREAD_LS)
504     ecc_fp_free();  /* free per thread cache */
505 #endif
506 
507 #ifdef CYASSL_TIRTOS
508     fdCloseSession(Task_self());
509 #endif
510 
511 #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
512     ((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
513     TicketCleanup();
514 #endif
515 
516 #ifdef WOLFSSL_ASYNC_CRYPT
517     wolfAsync_DevClose(&devId);
518 #endif
519 
520 #ifndef CYASSL_TIRTOS
521     return 0;
522 #endif
523 }
524 
525 #endif /* !NO_WOLFSSL_SERVER */
526 
527 
528 /* so overall tests can pull in test function */
529 #ifndef NO_MAIN_DRIVER
530 
main(int argc,char ** argv)531     int main(int argc, char** argv)
532     {
533         func_args args;
534 
535 #ifdef HAVE_WNR
536         if (wc_InitNetRandom(wnrConfig, NULL, 5000) != 0)
537             err_sys("Whitewood netRandom global config failed");
538 #endif
539 
540         StartTCP();
541 
542         args.argc = argc;
543         args.argv = argv;
544         args.return_code = 0;
545 
546         CyaSSL_Init();
547 #if defined(DEBUG_CYASSL) && !defined(CYASSL_MDK_SHELL)
548         CyaSSL_Debugging_ON();
549 #endif
550         ChangeToWolfRoot();
551 #ifndef NO_WOLFSSL_SERVER
552         echoserver_test(&args);
553 #endif
554         CyaSSL_Cleanup();
555 
556 #ifdef HAVE_WNR
557         if (wc_FreeNetRandom() < 0)
558             err_sys("Failed to free netRandom context");
559 #endif /* HAVE_WNR */
560 
561         return args.return_code;
562     }
563 
564 #endif /* NO_MAIN_DRIVER */
565