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