1 /*
2  * Copyright (C) 2004-2012 Free Software Foundation, Inc.
3  * Copyright (C) 2001,2002 Paul Sheer
4  * Copyright (C) 2016-2018 Red Hat, Inc.
5  * Portions Copyright (C) 2002,2003 Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * GnuTLS is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * GnuTLS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21  */
22 
23 /* This server is heavily modified for GnuTLS by Nikos Mavrogiannopoulos
24  * (which means it is quite unreadable)
25  */
26 
27 #include <config.h>
28 
29 #include "common.h"
30 #include "serv-args.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <string.h>
36 #include <gnutls/gnutls.h>
37 #include <gnutls/dtls.h>
38 #include <sys/time.h>
39 #include <sys/select.h>
40 #include <fcntl.h>
41 #include <list.h>
42 #include <netdb.h>
43 #include <unistd.h>
44 #include <socket.h>
45 
46 /* Gnulib portability files. */
47 #include "read-file.h"
48 #include "minmax.h"
49 #include "sockets.h"
50 #include "udp-serv.h"
51 
52 /* konqueror cannot handle sending the page in multiple
53  * pieces.
54  */
55 /* global stuff */
56 static int generate = 0;
57 static int http = 0;
58 static int x509ctype;
59 static int debug = 0;
60 
61 unsigned int verbose = 1;
62 static int nodb;
63 static int noticket;
64 static int earlydata;
65 int require_cert;
66 int disable_client_cert;
67 
68 const char *psk_passwd = NULL;
69 const char *srp_passwd = NULL;
70 const char *srp_passwd_conf = NULL;
71 const char **x509_keyfile = NULL;
72 const char **x509_certfile = NULL;
73 unsigned x509_certfile_size = 0;
74 unsigned x509_keyfile_size = 0;
75 const char *x509_cafile = NULL;
76 const char *dh_params_file = NULL;
77 const char *x509_crlfile = NULL;
78 const char *priorities = NULL;
79 const char **rawpk_keyfile = NULL;
80 const char **rawpk_file = NULL;
81 unsigned rawpk_keyfile_size = 0;
82 unsigned rawpk_file_size = 0;
83 
84 const char **ocsp_responses = NULL;
85 unsigned ocsp_responses_size = 0;
86 
87 const char *sni_hostname = NULL;
88 int sni_hostname_fatal = 0;
89 
90 const char **alpn_protos = NULL;
91 unsigned alpn_protos_size = 0;
92 
93 gnutls_datum_t session_ticket_key;
94 gnutls_anti_replay_t anti_replay;
95 int record_max_size;
96 const char *http_data_file = NULL;
97 static void tcp_server(const char *name, int port);
98 
99 /* end of globals */
100 
101 /* This is a sample TCP echo server.
102  * This will behave as an http server if any argument in the
103  * command line is present
104  */
105 
106 #define SMALL_READ_TEST (2147483647)
107 
108 #define GERR(ret) fprintf(stderr, "Error: %s\n", safe_strerror(ret))
109 
110 #define HTTP_END  "</BODY></HTML>\n\n"
111 
112 #define HTTP_UNIMPLEMENTED "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML><HEAD>\r\n<TITLE>501 Method Not Implemented</TITLE>\r\n</HEAD><BODY>\r\n<H1>Method Not Implemented</H1>\r\n<HR>\r\n</BODY></HTML>\r\n"
113 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
114 
115 #define HTTP_BEGIN HTTP_OK \
116 		"\n" \
117 		"<HTML><BODY>\n" \
118 		"<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
119 		"GnuTLS</a></H1></CENTER>\n\n"
120 
121 /* These are global */
122 gnutls_srp_server_credentials_t srp_cred = NULL;
123 gnutls_psk_server_credentials_t psk_cred = NULL;
124 #ifdef ENABLE_ANON
125 gnutls_anon_server_credentials_t dh_cred = NULL;
126 #endif
127 gnutls_certificate_credentials_t cert_cred = NULL;
128 
129 const int ssl_session_cache = 2048;
130 
131 static void wrap_db_init(void);
132 static void wrap_db_deinit(void);
133 static int wrap_db_store(void *dbf, gnutls_datum_t key,
134 			 gnutls_datum_t data);
135 static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key);
136 static int wrap_db_delete(void *dbf, gnutls_datum_t key);
137 static int anti_replay_db_add(void *dbf, time_t exp, const gnutls_datum_t *key,
138 			      const gnutls_datum_t *data);
139 
140 static void cmd_parser(int argc, char **argv);
141 
142 
143 #define HTTP_STATE_REQUEST	1
144 #define HTTP_STATE_RESPONSE	2
145 #define HTTP_STATE_CLOSING	3
146 
147 LIST_TYPE_DECLARE(listener_item, char *http_request; char *http_response;
148 		  int request_length; int response_length;
149 		  int response_written; int http_state;
150 		  int listen_socket; int fd;
151 		  gnutls_session_t tls_session;
152 		  int handshake_ok;
153 		  int close_ok;
154 		  time_t start;
155 		  int earlydata_eof;
156     );
157 
safe_strerror(int value)158 static const char *safe_strerror(int value)
159 {
160 	const char *ret = gnutls_strerror(value);
161 	if (ret == NULL)
162 		ret = str_unknown;
163 	return ret;
164 }
165 
listener_free(listener_item * j)166 static void listener_free(listener_item * j)
167 {
168 
169 	free(j->http_request);
170 	free(j->http_response);
171 	if (j->fd >= 0) {
172 		if (j->close_ok)
173 			gnutls_bye(j->tls_session, GNUTLS_SHUT_WR);
174 		shutdown(j->fd, 2);
175 		close(j->fd);
176 		gnutls_deinit(j->tls_session);
177 	}
178 }
179 
180 
181 /* we use primes up to 1024 in this server.
182  * otherwise we should add them here.
183  */
184 
185 gnutls_dh_params_t dh_params = NULL;
186 gnutls_rsa_params_t rsa_params = NULL;
187 
generate_dh_primes(void)188 static int generate_dh_primes(void)
189 {
190 	int prime_bits =
191 	    gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
192 					GNUTLS_SEC_PARAM_MEDIUM);
193 
194 	if (gnutls_dh_params_init(&dh_params) < 0) {
195 		fprintf(stderr, "Error in dh parameter initialization\n");
196 		exit(1);
197 	}
198 
199 	/* Generate Diffie-Hellman parameters - for use with DHE
200 	 * kx algorithms. These should be discarded and regenerated
201 	 * once a week or once a month. Depends on the
202 	 * security requirements.
203 	 */
204 	printf
205 	    ("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
206 	     prime_bits);
207 	fflush(stdout);
208 
209 	if (gnutls_dh_params_generate2(dh_params, prime_bits) < 0) {
210 		fprintf(stderr, "Error in prime generation\n");
211 		exit(1);
212 	}
213 
214 	return 0;
215 }
216 
read_dh_params(void)217 static void read_dh_params(void)
218 {
219 	char tmpdata[2048];
220 	int size;
221 	gnutls_datum_t params;
222 	FILE *fp;
223 
224 	if (gnutls_dh_params_init(&dh_params) < 0) {
225 		fprintf(stderr, "Error in dh parameter initialization\n");
226 		exit(1);
227 	}
228 
229 	/* read the params file
230 	 */
231 	fp = fopen(dh_params_file, "r");
232 	if (fp == NULL) {
233 		fprintf(stderr, "Could not open %s\n", dh_params_file);
234 		exit(1);
235 	}
236 
237 	size = fread(tmpdata, 1, sizeof(tmpdata) - 1, fp);
238 	tmpdata[size] = 0;
239 	fclose(fp);
240 
241 	params.data = (unsigned char *) tmpdata;
242 	params.size = size;
243 
244 	size =
245 	    gnutls_dh_params_import_pkcs3(dh_params, &params,
246 					  GNUTLS_X509_FMT_PEM);
247 
248 	if (size < 0) {
249 		fprintf(stderr, "Error parsing dh params: %s\n",
250 			safe_strerror(size));
251 		exit(1);
252 	}
253 
254 	printf("Read Diffie-Hellman parameters.\n");
255 	fflush(stdout);
256 
257 }
258 
259 static int
get_params(gnutls_session_t session,gnutls_params_type_t type,gnutls_params_st * st)260 get_params(gnutls_session_t session, gnutls_params_type_t type,
261 	   gnutls_params_st * st)
262 {
263 
264 	if (type == GNUTLS_PARAMS_DH) {
265 		if (dh_params == NULL)
266 			return -1;
267 		st->params.dh = dh_params;
268 	} else
269 		return -1;
270 
271 	st->type = type;
272 	st->deinit = 0;
273 
274 	return 0;
275 }
276 
277 LIST_DECLARE_INIT(listener_list, listener_item, listener_free);
278 
cert_verify_callback(gnutls_session_t session)279 static int cert_verify_callback(gnutls_session_t session)
280 {
281 listener_item * j = gnutls_session_get_ptr(session);
282 unsigned int size;
283 int ret;
284 
285 	if (gnutls_auth_get_type(session) == GNUTLS_CRD_CERTIFICATE) {
286 		if (!require_cert && gnutls_certificate_get_peers(session, &size) == NULL)
287 			return 0;
288 
289 		if (ENABLED_OPT(VERIFY_CLIENT_CERT)) {
290 			if (cert_verify(session, NULL, NULL) == 0) {
291 				do {
292 					ret = gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
293 				} while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
294 
295 				j->http_state = HTTP_STATE_CLOSING;
296 				return -1;
297 			}
298 		} else {
299 			printf("- Peer's certificate was NOT verified.\n");
300 		}
301 	}
302 	return 0;
303 }
304 
305 /* callback used to verify if the host name advertised in client hello matches
306  * the one configured in server
307  */
308 static int
post_client_hello(gnutls_session_t session)309 post_client_hello(gnutls_session_t session)
310 {
311 	int ret;
312 	/* DNS names (only type supported) may be at most 256 byte long */
313 	char *name;
314 	size_t len = 256;
315 	unsigned int type;
316 	int i;
317 
318 	name = malloc(len);
319 	if (name == NULL)
320 		return GNUTLS_E_MEMORY_ERROR;
321 
322 	for (i=0; ; ) {
323 		ret = gnutls_server_name_get(session, name, &len, &type, i);
324 		if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
325 			char *new_name;
326 			new_name = realloc(name, len);
327 			if (new_name == NULL) {
328 				ret = GNUTLS_E_MEMORY_ERROR;
329 				goto end;
330 			}
331 			name = new_name;
332 			continue; /* retry call with same index */
333 		}
334 
335 		/* check if it is the last entry in list */
336 		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
337 			break;
338 		i++;
339 		if (ret != GNUTLS_E_SUCCESS)
340 			goto end;
341 		/* unknown types need to be ignored */
342 		if (type != GNUTLS_NAME_DNS)
343 			continue;
344 
345 		if (strlen(sni_hostname) != len)
346 			continue;
347 		/* API guarantees that the name of type DNS will be null terminated */
348 		if (!strncmp(name, sni_hostname, len)) {
349 			ret = GNUTLS_E_SUCCESS;
350 			goto end;
351 		}
352 	};
353 	/* when there is no extension, we can't send the extension specific alert */
354 	if (i == 0) {
355 		fprintf(stderr, "Warning: client did not include SNI extension, using default host\n");
356 		ret = GNUTLS_E_SUCCESS;
357 		goto end;
358 	}
359 
360 	if (sni_hostname_fatal == 1) {
361 		/* abort the connection, propagate error up the stack */
362 		ret = GNUTLS_E_UNRECOGNIZED_NAME;
363 		goto end;
364 	}
365 
366 	fprintf(stderr, "Warning: client provided unrecognized host name\n");
367 	/* since we just want to send an alert, not abort the connection, we
368 	 * need to send it ourselves
369 	 */
370 	do {
371 		ret = gnutls_alert_send(session,
372 					GNUTLS_AL_WARNING,
373 					GNUTLS_A_UNRECOGNIZED_NAME);
374 	} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
375 
376 	/* continue handshake, fall through */
377 end:
378 	free(name);
379 	return ret;
380 }
381 
382 #define MAX_ALPN_PROTOCOLS 16
initialize_session(int dtls)383 gnutls_session_t initialize_session(int dtls)
384 {
385 	gnutls_session_t session;
386 	int ret;
387 	unsigned i;
388 	const char *err;
389 #ifdef ENABLE_ALPN
390 	gnutls_datum_t alpn[MAX_ALPN_PROTOCOLS];
391 #endif
392 	unsigned alpn_size;
393 	unsigned flags = GNUTLS_SERVER | GNUTLS_POST_HANDSHAKE_AUTH | GNUTLS_ENABLE_RAWPK;
394 
395 	if (dtls)
396 		flags |= GNUTLS_DATAGRAM;
397 
398 	if (earlydata)
399 		flags |= GNUTLS_ENABLE_EARLY_DATA;
400 
401 	gnutls_init(&session, flags);
402 
403 	/* allow the use of private ciphersuites.
404 	 */
405 	gnutls_handshake_set_private_extensions(session, 1);
406 
407 	gnutls_handshake_set_timeout(session,
408 				     GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
409 
410 	if (nodb == 0) {
411 		gnutls_db_set_retrieve_function(session, wrap_db_fetch);
412 		gnutls_db_set_remove_function(session, wrap_db_delete);
413 		gnutls_db_set_store_function(session, wrap_db_store);
414 		gnutls_db_set_ptr(session, NULL);
415 	}
416 
417 	if (noticket == 0)
418 		gnutls_session_ticket_enable_server(session,
419 						    &session_ticket_key);
420 
421 	if (earlydata) {
422 		gnutls_anti_replay_enable(session, anti_replay);
423 		if (HAVE_OPT(MAXEARLYDATA)) {
424 			ret = gnutls_record_set_max_early_data_size(session, OPT_VALUE_MAXEARLYDATA);
425 			if (ret < 0) {
426 				fprintf(stderr, "Could not set max early data size: %s\n", gnutls_strerror(ret));
427 				exit(1);
428 			}
429 		}
430 	}
431 
432 	if (sni_hostname != NULL)
433 		gnutls_handshake_set_post_client_hello_function(session,
434 								&post_client_hello);
435 
436 	if (priorities == NULL) {
437 		ret = gnutls_set_default_priority(session);
438 		if (ret < 0) {
439 			fprintf(stderr, "Could not set default policy: %s\n", gnutls_strerror(ret));
440 			exit(1);
441 		}
442 	} else {
443 		ret = gnutls_priority_set_direct(session, priorities, &err);
444 		if (ret < 0) {
445 			fprintf(stderr, "Syntax error at: %s\n", err);
446 			exit(1);
447 		}
448 	}
449 
450 #ifndef ENABLE_ALPN
451 	if (alpn_protos_size != 0) {
452 		fprintf(stderr, "ALPN is not supported\n");
453 		exit(1);
454 	}
455 #else
456 	alpn_size = MIN(MAX_ALPN_PROTOCOLS,alpn_protos_size);
457 	for (i=0;i<alpn_size;i++) {
458 		alpn[i].data = (void*)alpn_protos[i];
459 		alpn[i].size = strlen(alpn_protos[i]);
460 	}
461 
462 	ret = gnutls_alpn_set_protocols(session, alpn, alpn_size, HAVE_OPT(ALPN_FATAL)?GNUTLS_ALPN_MANDATORY:0);
463 	if (ret < 0) {
464 		fprintf(stderr, "Error setting ALPN protocols: %s\n", gnutls_strerror(ret));
465 		exit(1);
466 	}
467 #endif
468 
469 #ifdef ENABLE_ANON
470 	gnutls_credentials_set(session, GNUTLS_CRD_ANON, dh_cred);
471 #endif
472 
473 	if (srp_cred != NULL)
474 		gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred);
475 
476 	if (psk_cred != NULL)
477 		gnutls_credentials_set(session, GNUTLS_CRD_PSK, psk_cred);
478 
479 	if (cert_cred != NULL) {
480 		gnutls_certificate_set_verify_function(cert_cred,
481 					       cert_verify_callback);
482 
483 		gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
484 				       cert_cred);
485 	}
486 
487 	if (disable_client_cert)
488 		gnutls_certificate_server_set_request(session,
489 						      GNUTLS_CERT_IGNORE);
490 	else {
491 		if (require_cert)
492 			gnutls_certificate_server_set_request(session,
493 							      GNUTLS_CERT_REQUIRE);
494 		else
495 			gnutls_certificate_server_set_request(session,
496 							      GNUTLS_CERT_REQUEST);
497 	}
498 
499 	/* use the record size limit extension */
500 	if (record_max_size > 0) {
501 		if (gnutls_record_set_max_recv_size(session, record_max_size) <
502 		    0) {
503 			fprintf(stderr,
504 				"Cannot set the maximum record receive size to %d.\n",
505 				record_max_size);
506 			exit(1);
507 		}
508 	}
509 
510 	if (HAVE_OPT(HEARTBEAT))
511 		gnutls_heartbeat_enable(session,
512 					GNUTLS_HB_PEER_ALLOWED_TO_SEND);
513 
514 #ifdef ENABLE_DTLS_SRTP
515 	if (HAVE_OPT(SRTP_PROFILES)) {
516 		ret =
517 		    gnutls_srtp_set_profile_direct(session,
518 						   OPT_ARG(SRTP_PROFILES),
519 						   &err);
520 		if (ret == GNUTLS_E_INVALID_REQUEST)
521 			fprintf(stderr, "Syntax error at: %s\n", err);
522 		else if (ret != 0)
523 			fprintf(stderr, "Error in profiles: %s\n",
524 				gnutls_strerror(ret));
525 		else fprintf(stderr,"DTLS profile set to %s\n",
526 			     OPT_ARG(SRTP_PROFILES));
527 
528 		if (ret != 0) exit(1);
529 	}
530 #endif
531 
532 
533 	return session;
534 }
535 
536 #include <gnutls/x509.h>
537 
538 static const char DEFAULT_DATA[] =
539     "This is the default message reported by the GnuTLS implementation. "
540     "For more information please visit "
541     "<a href=\"https://www.gnutls.org/\">https://www.gnutls.org/</a>.";
542 
543 /* Creates html with the current session information.
544  */
545 #define tmp_buffer &http_buffer[strlen(http_buffer)]
546 #define tmp_buffer_size len-strlen(http_buffer)
peer_print_info(gnutls_session_t session,int * ret_length,const char * header)547 static char *peer_print_info(gnutls_session_t session, int *ret_length,
548 			     const char *header)
549 {
550 	const char *tmp;
551 	unsigned char sesid[32];
552 	size_t i, sesid_size;
553 	char *http_buffer, *desc;
554 	gnutls_kx_algorithm_t kx_alg;
555 	size_t len = 20 * 1024 + strlen(header);
556 	char *crtinfo = NULL, *crtinfo_old = NULL;
557 	gnutls_protocol_t version;
558 	size_t ncrtinfo = 0;
559 
560 	if (verbose == 0) {
561 		http_buffer = malloc(len);
562 		if (http_buffer == NULL)
563 			return NULL;
564 
565 		strcpy(http_buffer, HTTP_BEGIN);
566 		strcpy(&http_buffer[sizeof(HTTP_BEGIN) - 1], DEFAULT_DATA);
567 		strcpy(&http_buffer
568 		       [sizeof(HTTP_BEGIN) + sizeof(DEFAULT_DATA) - 2],
569 		       HTTP_END);
570 		*ret_length =
571 		    sizeof(DEFAULT_DATA) + sizeof(HTTP_BEGIN) +
572 		    sizeof(HTTP_END) - 3;
573 		return http_buffer;
574 	}
575 
576 	if (gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT) == GNUTLS_CRT_X509) {
577 		const gnutls_datum_t *cert_list;
578 		unsigned int cert_list_size = 0;
579 
580 		cert_list =
581 		    gnutls_certificate_get_peers(session, &cert_list_size);
582 
583 		for (i = 0; i < cert_list_size; i++) {
584 			gnutls_x509_crt_t cert = NULL;
585 			gnutls_datum_t info;
586 
587 			if (gnutls_x509_crt_init(&cert) == 0 &&
588 			    gnutls_x509_crt_import(cert, &cert_list[i],
589 						   GNUTLS_X509_FMT_DER) ==
590 			    0
591 			    && gnutls_x509_crt_print(cert,
592 						     GNUTLS_CRT_PRINT_FULL,
593 						     &info) == 0) {
594 				const char *post = "</PRE><P><PRE>";
595 
596 				crtinfo_old = crtinfo;
597 				crtinfo =
598 				    realloc(crtinfo,
599 					    ncrtinfo + info.size +
600 					    strlen(post) + 1);
601 				if (crtinfo == NULL) {
602 					free(crtinfo_old);
603 					return NULL;
604 				}
605 				memcpy(crtinfo + ncrtinfo, info.data,
606 				       info.size);
607 				ncrtinfo += info.size;
608 				memcpy(crtinfo + ncrtinfo, post,
609 				       strlen(post));
610 				ncrtinfo += strlen(post);
611 				crtinfo[ncrtinfo] = '\0';
612 				gnutls_free(info.data);
613 			}
614 			gnutls_x509_crt_deinit(cert);
615 		}
616 	}
617 
618 	http_buffer = malloc(len);
619 	if (http_buffer == NULL) {
620 		free(crtinfo);
621 		return NULL;
622 	}
623 
624 	strcpy(http_buffer, HTTP_BEGIN);
625 
626 	version = gnutls_protocol_get_version(session);
627 
628 	/* print session_id */
629 	sesid_size = sizeof(sesid);
630 	gnutls_session_get_id(session, sesid, &sesid_size);
631 	snprintf(tmp_buffer, tmp_buffer_size, "\n<p>Session ID: <i>");
632 	for (i = 0; i < sesid_size; i++)
633 		snprintf(tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
634 	snprintf(tmp_buffer, tmp_buffer_size, "</i></p>\n");
635 	snprintf(tmp_buffer, tmp_buffer_size,
636 		 "<h5>If your browser supports session resumption, then you should see the "
637 		 "same session ID, when you press the <b>reload</b> button.</h5>\n");
638 
639 	/* Here unlike print_info() we use the kx algorithm to distinguish
640 	 * the functions to call.
641 	 */
642 	{
643 		char dns[256];
644 		size_t dns_size = sizeof(dns);
645 		unsigned int type;
646 
647 		if (gnutls_server_name_get
648 		    (session, dns, &dns_size, &type, 0) == 0) {
649 			snprintf(tmp_buffer, tmp_buffer_size,
650 				 "\n<p>Server Name: %s</p>\n", dns);
651 		}
652 
653 	}
654 
655 	kx_alg = gnutls_kx_get(session);
656 
657 	/* print srp specific data */
658 #ifdef ENABLE_SRP
659 	if (kx_alg == GNUTLS_KX_SRP) {
660 		snprintf(tmp_buffer, tmp_buffer_size,
661 			 "<p>Connected as user '%s'.</p>\n",
662 			 gnutls_srp_server_get_username(session));
663 	}
664 #endif
665 
666 #ifdef ENABLE_PSK
667 	if (kx_alg == GNUTLS_KX_PSK && gnutls_psk_server_get_username(session)) {
668 		snprintf(tmp_buffer, tmp_buffer_size,
669 			 "<p>Connected as user '%s'.</p>\n",
670 			 gnutls_psk_server_get_username(session));
671 	}
672 #endif
673 
674 
675 	/* print session information */
676 	strcat(http_buffer, "<P>\n");
677 
678 	tmp =
679 	    gnutls_protocol_get_name(version);
680 	if (tmp == NULL)
681 		tmp = str_unknown;
682 	snprintf(tmp_buffer, tmp_buffer_size,
683 		 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
684 		 tmp);
685 
686 	desc = gnutls_session_get_desc(session);
687 	if (desc) {
688 		snprintf(tmp_buffer, tmp_buffer_size,
689 			"<TR><TD>Description:</TD><TD>%s</TD></TR>\n",
690 			desc);
691 		gnutls_free(desc);
692 	}
693 
694 	if (gnutls_auth_get_type(session) == GNUTLS_CRD_CERTIFICATE &&
695 	    gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT) != GNUTLS_CRT_X509) {
696 		tmp =
697 		    gnutls_certificate_type_get_name
698 		    (gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT));
699 		if (tmp == NULL)
700 			tmp = str_unknown;
701 		snprintf(tmp_buffer, tmp_buffer_size,
702 			 "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n",
703 			 tmp);
704 	}
705 
706 	if (version < GNUTLS_TLS1_3) {
707 		tmp = gnutls_kx_get_name(kx_alg);
708 		if (tmp == NULL)
709 			tmp = str_unknown;
710 		snprintf(tmp_buffer, tmp_buffer_size,
711 			 "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
712 
713 #ifdef ENABLE_ANON
714 		if (kx_alg == GNUTLS_KX_ANON_DH) {
715 			snprintf(tmp_buffer, tmp_buffer_size,
716 				 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
717 				 gnutls_dh_get_prime_bits(session));
718 		}
719 #endif
720 
721 #if defined(ENABLE_DHE) || defined(ENABLE_ANON)
722 		if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS) {
723 			snprintf(tmp_buffer, tmp_buffer_size,
724 				 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
725 				 gnutls_dh_get_prime_bits(session));
726 		}
727 #endif
728 
729 		tmp = gnutls_compression_get_name(gnutls_compression_get(session));
730 		if (tmp == NULL)
731 			tmp = str_unknown;
732 		snprintf(tmp_buffer, tmp_buffer_size,
733 			 "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
734 
735 		tmp = gnutls_cipher_suite_get_name(kx_alg,
736 						   gnutls_cipher_get(session),
737 						   gnutls_mac_get(session));
738 		if (tmp == NULL)
739 			tmp = str_unknown;
740 		snprintf(tmp_buffer, tmp_buffer_size,
741 			 "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR>\n",
742 			 tmp);
743 	}
744 
745 	tmp = gnutls_cipher_get_name(gnutls_cipher_get(session));
746 	if (tmp == NULL)
747 		tmp = str_unknown;
748 	snprintf(tmp_buffer, tmp_buffer_size,
749 		 "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
750 
751 	tmp = gnutls_mac_get_name(gnutls_mac_get(session));
752 	if (tmp == NULL)
753 		tmp = str_unknown;
754 	snprintf(tmp_buffer, tmp_buffer_size,
755 		 "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
756 
757 	snprintf(tmp_buffer, tmp_buffer_size,
758 		 "</TABLE></P>\n");
759 
760 	if (crtinfo) {
761 		snprintf(tmp_buffer, tmp_buffer_size,
762 			 "<hr><PRE>%s\n</PRE>\n", crtinfo);
763 		free(crtinfo);
764 	}
765 
766 	snprintf(tmp_buffer, tmp_buffer_size,
767 		 "<hr><P>Your HTTP header was:<PRE>%s</PRE></P>\n"
768 		 HTTP_END, header);
769 
770 	*ret_length = strlen(http_buffer);
771 
772 	return http_buffer;
773 }
774 
peer_print_data(gnutls_session_t session,int * ret_length)775 static char *peer_print_data(gnutls_session_t session, int *ret_length)
776 {
777 	gnutls_datum_t data;
778 	char *http_buffer;
779 	size_t len;
780 	int ret;
781 
782 	ret = gnutls_load_file(http_data_file, &data);
783 	if (ret < 0) {
784 		ret = asprintf(&http_buffer,
785 			       "HTTP/1.0 404 Not Found\r\n"
786 			       "Content-type: text/html\r\n"
787 			       "\r\n"
788 			       "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
789 			       "<BODY><H1>Couldn't read %s</H1></BODY></HTML>\n\n",
790 			       http_data_file);
791 		if (ret < 0)
792 			return NULL;
793 
794 		*ret_length = strlen(http_buffer);
795 		return http_buffer;
796 	}
797 
798 	ret = asprintf(&http_buffer,
799 		       "HTTP/1.0 200 OK\r\n"
800 		       "Content-Type: application/octet-stream\r\n"
801 		       "Content-Length: %u\r\n"
802 		       "\r\n",
803 		       data.size);
804 	if (ret < 0)
805 		return NULL;
806 	len = ret;
807 	http_buffer = realloc(http_buffer, len + data.size);
808 	memcpy(&http_buffer[len], data.data, data.size);
809 	gnutls_free(data.data);
810 	*ret_length = len + data.size;
811 	return http_buffer;
812 }
813 
human_addr(const struct sockaddr * sa,socklen_t salen,char * buf,size_t buflen)814 const char *human_addr(const struct sockaddr *sa, socklen_t salen,
815 		       char *buf, size_t buflen)
816 {
817 	const char *save_buf = buf;
818 	size_t l;
819 
820 	if (!buf || !buflen)
821 		return "(error)";
822 
823 	*buf = 0;
824 
825 	switch (sa->sa_family) {
826 #if HAVE_IPV6
827 	case AF_INET6:
828 		snprintf(buf, buflen, "IPv6 ");
829 		break;
830 #endif
831 
832 	case AF_INET:
833 		snprintf(buf, buflen, "IPv4 ");
834 		break;
835 	}
836 
837 	l = 5;
838 	buf += l;
839 	buflen -= l;
840 
841 	if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) !=
842 	    0) {
843 		return "(error)";
844 	}
845 
846 	l = strlen(buf);
847 	buf += l;
848 	buflen -= l;
849 
850 	if (buflen < 8)
851 		return save_buf;
852 
853 	strcat(buf, " port ");
854 	buf += 6;
855 	buflen -= 6;
856 
857 	if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) !=
858 	    0) {
859 		snprintf(buf, buflen, "%s", " unknown");
860 	}
861 
862 	return save_buf;
863 }
864 
wait_for_connection(void)865 int wait_for_connection(void)
866 {
867 	listener_item *j;
868 	fd_set rd, wr;
869 	int n, sock = -1;
870 
871 	FD_ZERO(&rd);
872 	FD_ZERO(&wr);
873 	n = 0;
874 
875 	lloopstart(listener_list, j) {
876 		if (j->listen_socket) {
877 			FD_SET(j->fd, &rd);
878 			n = MAX(n, j->fd);
879 		}
880 	}
881 	lloopend(listener_list, j);
882 
883 	/* waiting part */
884 	n = select(n + 1, &rd, &wr, NULL, NULL);
885 	if (n == -1 && errno == EINTR)
886 		return -1;
887 	if (n < 0) {
888 		perror("select()");
889 		exit(1);
890 	}
891 
892 	/* find which one is ready */
893 	lloopstart(listener_list, j) {
894 		/* a new connection has arrived */
895 		if (FD_ISSET(j->fd, &rd) && j->listen_socket) {
896 			sock = j->fd;
897 			break;
898 		}
899 	}
900 	lloopend(listener_list, j);
901 	return sock;
902 }
903 
listen_socket(const char * name,int listen_port,int socktype)904 int listen_socket(const char *name, int listen_port, int socktype)
905 {
906 	struct addrinfo hints, *res, *ptr;
907 	char portname[6];
908 	int s = -1;
909 	int yes;
910 	listener_item *j = NULL;
911 
912 	snprintf(portname, sizeof(portname), "%d", listen_port);
913 	memset(&hints, 0, sizeof(hints));
914 	hints.ai_socktype = socktype;
915 	hints.ai_flags = AI_PASSIVE;
916 
917 	if ((s = getaddrinfo(NULL, portname, &hints, &res)) != 0) {
918 		fprintf(stderr, "getaddrinfo() failed: %s\n",
919 			gai_strerror(s));
920 		return -1;
921 	}
922 
923 	for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
924 		int news;
925 #ifndef HAVE_IPV6
926 		if (ptr->ai_family != AF_INET)
927 			continue;
928 #endif
929 
930 		/* Print what we are doing. */
931 		{
932 			char topbuf[512];
933 
934 			fprintf(stderr, "%s listening on %s...",
935 				name, human_addr(ptr->ai_addr,
936 						 ptr->ai_addrlen, topbuf,
937 						 sizeof(topbuf)));
938 		}
939 
940 		if ((news = socket(ptr->ai_family, ptr->ai_socktype,
941 				ptr->ai_protocol)) < 0) {
942 			perror("socket() failed");
943 			continue;
944 		}
945 		s = news; /* to not overwrite existing s from previous loops */
946 #if defined(HAVE_IPV6) && !defined(_WIN32)
947 		if (ptr->ai_family == AF_INET6) {
948 			yes = 1;
949 			/* avoid listen on ipv6 addresses failing
950 			 * because already listening on ipv4 addresses: */
951 			(void)setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
952 				   (const void *) &yes, sizeof(yes));
953 		}
954 #endif
955 
956 		if (socktype == SOCK_STREAM) {
957 			yes = 1;
958 			if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
959 				       (const void *) &yes,
960 				       sizeof(yes)) < 0) {
961 				perror("setsockopt() failed");
962 				close(s);
963 				continue;
964 			}
965 		} else {
966 #if defined(IP_DONTFRAG)
967 			yes = 1;
968 			if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
969 				       (const void *) &yes,
970 				       sizeof(yes)) < 0)
971 				perror("setsockopt(IP_DF) failed");
972 #elif defined(IP_MTU_DISCOVER)
973 			yes = IP_PMTUDISC_DO;
974 			if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
975 				       (const void *) &yes,
976 				       sizeof(yes)) < 0)
977 				perror("setsockopt(IP_DF) failed");
978 #endif
979 		}
980 
981 		if (bind(s, ptr->ai_addr, ptr->ai_addrlen) < 0) {
982 			perror("bind() failed");
983 			close(s);
984 			continue;
985 		}
986 
987 		if (socktype == SOCK_STREAM) {
988 			if (listen(s, 10) < 0) {
989 				perror("listen() failed");
990 				exit(1);
991 			}
992 		}
993 
994 		/* new list entry for the connection */
995 		lappend(listener_list);
996 		j = listener_list.tail;
997 		j->listen_socket = 1;
998 		j->fd = s;
999 
1000 		/* Complete earlier message. */
1001 		fprintf(stderr, "done\n");
1002 	}
1003 
1004 	fflush(stderr);
1005 
1006 	freeaddrinfo(res);
1007 
1008 	return s;
1009 }
1010 
1011 /* strips \r\n from the end of the string
1012  */
strip(char * data)1013 static void strip(char *data)
1014 {
1015 	int i;
1016 	int len = strlen(data);
1017 
1018 	for (i = 0; i < len; i++) {
1019 		if (data[i] == '\r' && data[i + 1] == '\n'
1020 		    && data[i + 2] == 0) {
1021 			data[i] = '\n';
1022 			data[i + 1] = 0;
1023 			break;
1024 		}
1025 	}
1026 }
1027 
1028 static unsigned
get_response(gnutls_session_t session,char * request,char ** response,int * response_length)1029 get_response(gnutls_session_t session, char *request,
1030 	     char **response, int *response_length)
1031 {
1032 	char *p, *h;
1033 
1034 	if (http != 0) {
1035 		if (strncmp(request, "GET ", 4))
1036 			goto unimplemented;
1037 
1038 		if (!(h = strchr(request, '\n')))
1039 			goto unimplemented;
1040 
1041 		*h++ = '\0';
1042 		while (*h == '\r' || *h == '\n')
1043 			h++;
1044 
1045 		if (!(p = strchr(request + 4, ' ')))
1046 			goto unimplemented;
1047 		*p = '\0';
1048 	}
1049 
1050 	if (http != 0) {
1051 		if (http_data_file == NULL)
1052 			*response = peer_print_info(session, response_length, h);
1053 		else
1054 			*response = peer_print_data(session, response_length);
1055 	} else {
1056 		int ret;
1057 		strip(request);
1058 		fprintf(stderr, "received cmd: %s\n", request);
1059 
1060 		ret = check_command(session, request, disable_client_cert);
1061 		if (ret > 0) {
1062 			*response = strdup("Successfully executed command\n");
1063 			if (*response == NULL) {
1064 				fprintf(stderr, "Memory error\n");
1065 				return 0;
1066 			}
1067 			*response_length = strlen(*response);
1068 			return 1;
1069 		} else if (ret == 0) {
1070 			*response = strdup(request);
1071 			if (*response == NULL) {
1072 				fprintf(stderr, "Memory error\n");
1073 				return 0;
1074 			}
1075 			*response_length = strlen(*response);
1076 		} else {
1077 			*response = NULL;
1078 			do {
1079 				ret = gnutls_alert_send_appropriate(session, ret);
1080 			} while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
1081 			return 0;
1082 		}
1083 	}
1084 
1085 	return 1;
1086 
1087       unimplemented:
1088 	*response = strdup(HTTP_UNIMPLEMENTED);
1089 	if (*response == NULL)
1090 		return 0;
1091 	*response_length = ((*response) ? strlen(*response) : 0);
1092 	return 1;
1093 }
1094 
1095 static void terminate(int sig) __attribute__ ((__noreturn__));
1096 
terminate(int sig)1097 static void terminate(int sig)
1098 {
1099 	fprintf(stderr, "Exiting via signal %d\n", sig);
1100 	exit(1);
1101 }
1102 
1103 
check_alert(gnutls_session_t session,int ret)1104 static void check_alert(gnutls_session_t session, int ret)
1105 {
1106 	if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
1107 	    || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
1108 		int last_alert = gnutls_alert_get(session);
1109 		if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
1110 		    ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
1111 			printf
1112 			    ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
1113 		else
1114 			printf("* Received alert '%d': %s.\n", last_alert,
1115 			       gnutls_alert_get_name(last_alert));
1116 	}
1117 }
1118 
tls_log_func(int level,const char * str)1119 static void tls_log_func(int level, const char *str)
1120 {
1121 	fprintf(stderr, "|<%d>| %s", level, str);
1122 }
1123 
tls_audit_log_func(gnutls_session_t session,const char * str)1124 static void tls_audit_log_func(gnutls_session_t session, const char *str)
1125 {
1126 	fprintf(stderr, "|<%p>| %s", session, str);
1127 }
1128 
main(int argc,char ** argv)1129 int main(int argc, char **argv)
1130 {
1131 	int ret, mtu, port;
1132 	char name[256];
1133 	int cert_set = 0;
1134 	unsigned use_static_dh_params = 0;
1135 	unsigned i;
1136 
1137 	cmd_parser(argc, argv);
1138 
1139 #ifndef _WIN32
1140 	signal(SIGHUP, SIG_IGN);
1141 	signal(SIGTERM, terminate);
1142 	if (signal(SIGINT, terminate) == SIG_IGN)
1143 		signal(SIGINT, SIG_IGN);	/* e.g. background process */
1144 #endif
1145 
1146 	sockets_init();
1147 
1148 	if (nodb == 0)
1149 		wrap_db_init();
1150 
1151 	if (HAVE_OPT(UDP))
1152 		strcpy(name, "UDP ");
1153 	else
1154 		name[0] = 0;
1155 
1156 	if (http == 1) {
1157 		strcat(name, "HTTP Server");
1158 	} else {
1159 		strcat(name, "Echo Server");
1160 	}
1161 
1162 	gnutls_global_set_log_function(tls_log_func);
1163 	gnutls_global_set_audit_log_function(tls_audit_log_func);
1164 	gnutls_global_set_log_level(debug);
1165 
1166 	if ((ret = gnutls_global_init()) < 0) {
1167 		fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret));
1168 		exit(1);
1169 	}
1170 #ifdef ENABLE_PKCS11
1171 	if (HAVE_OPT(PROVIDER)) {
1172 		ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
1173 		if (ret < 0)
1174 			fprintf(stderr, "pkcs11_init: %s",
1175 				gnutls_strerror(ret));
1176 		else {
1177 			ret =
1178 			    gnutls_pkcs11_add_provider(OPT_ARG(PROVIDER),
1179 						       NULL);
1180 			if (ret < 0) {
1181 				fprintf(stderr, "pkcs11_add_provider: %s",
1182 					gnutls_strerror(ret));
1183 				exit(1);
1184 			}
1185 		}
1186 	}
1187 	pkcs11_common(NULL);
1188 #endif
1189 
1190 	/* Note that servers must generate parameters for
1191 	 * Diffie-Hellman. See gnutls_dh_params_generate(), and
1192 	 * gnutls_dh_params_set().
1193 	 */
1194 	if (generate != 0) {
1195 		generate_dh_primes();
1196 	} else if (dh_params_file) {
1197 		read_dh_params();
1198 	} else {
1199 		use_static_dh_params = 1;
1200 	}
1201 
1202 	if (gnutls_certificate_allocate_credentials(&cert_cred) < 0) {
1203 		fprintf(stderr, "memory error\n");
1204 		exit(1);
1205 	}
1206 
1207 	/* X509 credentials */
1208 	if (x509_cafile != NULL) {
1209 		if ((ret = gnutls_certificate_set_x509_trust_file
1210 		     (cert_cred, x509_cafile, x509ctype)) < 0) {
1211 			fprintf(stderr, "Error reading '%s'\n",
1212 				x509_cafile);
1213 			GERR(ret);
1214 			exit(1);
1215 		} else {
1216 			printf("Processed %d CA certificate(s).\n", ret);
1217 		}
1218 	}
1219 	if (x509_crlfile != NULL) {
1220 		if ((ret = gnutls_certificate_set_x509_crl_file
1221 		     (cert_cred, x509_crlfile, x509ctype)) < 0) {
1222 			fprintf(stderr, "Error reading '%s'\n",
1223 				x509_crlfile);
1224 			GERR(ret);
1225 			exit(1);
1226 		} else {
1227 			printf("Processed %d CRL(s).\n", ret);
1228 		}
1229 	}
1230 
1231 	if (x509_certfile_size > 0 && x509_keyfile_size > 0) {
1232 		for (i = 0; i < x509_certfile_size; i++) {
1233 			ret = gnutls_certificate_set_x509_key_file
1234 			    (cert_cred, x509_certfile[i], x509_keyfile[i], x509ctype);
1235 			if (ret < 0) {
1236 				fprintf(stderr,
1237 						"Error reading '%s' or '%s'\n",
1238 						x509_certfile[i], x509_keyfile[i]);
1239 				GERR(ret);
1240 				exit(1);
1241 			} else
1242 				cert_set = 1;
1243 		}
1244 	}
1245 
1246 	/* Raw public-key credentials */
1247 	if (rawpk_file_size > 0 && rawpk_keyfile_size > 0) {
1248 		for (i = 0; i < rawpk_keyfile_size; i++) {
1249 			ret = gnutls_certificate_set_rawpk_key_file(cert_cred, rawpk_file[i],
1250 			                                            rawpk_keyfile[i],
1251 			                                            x509ctype,
1252 			                                            NULL, 0, NULL, 0,
1253 			                                            0, 0);
1254 			if (ret < 0) {
1255 				fprintf(stderr,	"Error reading '%s' or '%s'\n",
1256 				        rawpk_file[i], rawpk_keyfile[i]);
1257 					GERR(ret);
1258 					exit(1);
1259 			} else {
1260 				cert_set = 1;
1261 			}
1262 		}
1263 	}
1264 
1265 	if (cert_set == 0) {
1266 		fprintf(stderr,
1267 			"Warning: no private key and certificate pairs were set.\n");
1268 	}
1269 
1270 #ifndef ENABLE_OCSP
1271 	if (HAVE_OPT(IGNORE_OCSP_RESPONSE_ERRORS) || ocsp_responses_size != 0) {
1272 		fprintf(stderr, "OCSP is not supported!\n");
1273 			exit(1);
1274 	}
1275 #else
1276 	/* OCSP status-request TLS extension */
1277 	if (HAVE_OPT(IGNORE_OCSP_RESPONSE_ERRORS))
1278 		gnutls_certificate_set_flags(cert_cred, GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK);
1279 
1280 	for (i = 0; i < ocsp_responses_size; i++ ) {
1281 		ret = gnutls_certificate_set_ocsp_status_request_file
1282 		    (cert_cred, ocsp_responses[i], 0);
1283 		if (ret < 0) {
1284 			fprintf(stderr,
1285 				"Cannot set OCSP status request file: %s: %s\n",
1286 				ocsp_responses[i],
1287 				gnutls_strerror(ret));
1288 			exit(1);
1289 		}
1290 	}
1291 #endif
1292 
1293 	if (use_static_dh_params) {
1294 #if defined(ENABLE_DHE) || defined(ENABLE_ANON)
1295 		ret = gnutls_certificate_set_known_dh_params(cert_cred, GNUTLS_SEC_PARAM_MEDIUM);
1296 		if (ret < 0) {
1297 			fprintf(stderr, "Error while setting DH parameters: %s\n", gnutls_strerror(ret));
1298 			exit(1);
1299 		}
1300 #else
1301 		fprintf(stderr, "Setting DH parameters is not supported\n");
1302 		exit(1);
1303 #endif
1304 	} else {
1305 		gnutls_certificate_set_params_function(cert_cred, get_params);
1306 	}
1307 
1308 	/* this is a password file (created with the included srpcrypt utility)
1309 	 * Read README.crypt prior to using SRP.
1310 	 */
1311 #ifdef ENABLE_SRP
1312 	if (srp_passwd != NULL) {
1313 		gnutls_srp_allocate_server_credentials(&srp_cred);
1314 
1315 		if ((ret =
1316 		     gnutls_srp_set_server_credentials_file(srp_cred,
1317 							    srp_passwd,
1318 							    srp_passwd_conf))
1319 		    < 0) {
1320 			/* only exit is this function is not disabled
1321 			 */
1322 			fprintf(stderr,
1323 				"Error while setting SRP parameters\n");
1324 			GERR(ret);
1325 		}
1326 	}
1327 #endif
1328 
1329 	/* this is a password file
1330 	 */
1331 #ifdef ENABLE_PSK
1332 	if (psk_passwd != NULL) {
1333 		gnutls_psk_allocate_server_credentials(&psk_cred);
1334 
1335 		if ((ret =
1336 		     gnutls_psk_set_server_credentials_file(psk_cred,
1337 							    psk_passwd)) <
1338 		    0) {
1339 			/* only exit is this function is not disabled
1340 			 */
1341 			fprintf(stderr,
1342 				"Error while setting PSK parameters\n");
1343 			GERR(ret);
1344 		}
1345 
1346 		if (HAVE_OPT(PSKHINT)) {
1347 			ret =
1348 			    gnutls_psk_set_server_credentials_hint
1349 			    (psk_cred, OPT_ARG(PSKHINT));
1350 			if (ret) {
1351 				fprintf(stderr,
1352 					"Error setting PSK identity hint.\n");
1353 				GERR(ret);
1354 			}
1355 		}
1356 
1357 		if (use_static_dh_params) {
1358 			ret = gnutls_psk_set_server_known_dh_params(psk_cred, GNUTLS_SEC_PARAM_MEDIUM);
1359 			if (ret < 0) {
1360 				fprintf(stderr, "Error while setting DH parameters: %s\n", gnutls_strerror(ret));
1361 				exit(1);
1362 			}
1363 		} else {
1364 			gnutls_psk_set_server_params_function(psk_cred,
1365 							      get_params);
1366 		}
1367 	}
1368 #endif
1369 
1370 #ifdef ENABLE_ANON
1371 	gnutls_anon_allocate_server_credentials(&dh_cred);
1372 
1373 	if (use_static_dh_params) {
1374 		ret = gnutls_anon_set_server_known_dh_params(dh_cred, GNUTLS_SEC_PARAM_MEDIUM);
1375 		if (ret < 0) {
1376 			fprintf(stderr, "Error while setting DH parameters: %s\n", gnutls_strerror(ret));
1377 			exit(1);
1378 		}
1379 	} else {
1380 		gnutls_anon_set_server_params_function(dh_cred, get_params);
1381 	}
1382 #endif
1383 
1384 	if (noticket == 0)
1385 		gnutls_session_ticket_key_generate(&session_ticket_key);
1386 
1387 	if (earlydata) {
1388 		ret = gnutls_anti_replay_init(&anti_replay);
1389 		if (ret < 0) {
1390 			fprintf(stderr, "Error while initializing anti-replay: %s\n", gnutls_strerror(ret));
1391 			exit(1);
1392 		}
1393 		gnutls_anti_replay_set_add_function(anti_replay, anti_replay_db_add);
1394 		gnutls_anti_replay_set_ptr(anti_replay, NULL);
1395 	}
1396 
1397 	if (HAVE_OPT(MTU))
1398 		mtu = OPT_VALUE_MTU;
1399 	else
1400 		mtu = 1300;
1401 
1402 	if (HAVE_OPT(PORT))
1403 		port = OPT_VALUE_PORT;
1404 	else
1405 		port = 5556;
1406 
1407 	if (HAVE_OPT(UDP))
1408 		udp_server(name, port, mtu);
1409 	else
1410 		tcp_server(name, port);
1411 
1412 	return 0;
1413 }
1414 
retry_handshake(listener_item * j)1415 static void retry_handshake(listener_item *j)
1416 {
1417 	int r, ret;
1418 
1419 	r = gnutls_handshake(j->tls_session);
1420 	if (r < 0 && gnutls_error_is_fatal(r) == 0) {
1421 		check_alert(j->tls_session, r);
1422 		/* nothing */
1423 	} else if (r < 0) {
1424 		j->http_state = HTTP_STATE_CLOSING;
1425 		check_alert(j->tls_session, r);
1426 		fprintf(stderr, "Error in handshake: %s\n", gnutls_strerror(r));
1427 
1428 		do {
1429 			ret = gnutls_alert_send_appropriate(j->tls_session, r);
1430 		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
1431 		j->close_ok = 0;
1432 	} else if (r == 0) {
1433 		if (gnutls_session_is_resumed(j->tls_session) != 0 && verbose != 0)
1434 			printf("*** This is a resumed session\n");
1435 
1436 		if (verbose != 0) {
1437 #if 0
1438 			printf("- connection from %s\n",
1439 			     human_addr((struct sockaddr *)
1440 				&client_address,
1441 				calen,
1442 				topbuf,
1443 				sizeof(topbuf)));
1444 #endif
1445 
1446 			print_info(j->tls_session, verbose, verbose);
1447 
1448 			if (HAVE_OPT(KEYMATEXPORT))
1449 				print_key_material(j->tls_session,
1450 						   OPT_ARG(KEYMATEXPORT),
1451 						   HAVE_OPT(KEYMATEXPORTSIZE) ?
1452 						   OPT_VALUE_KEYMATEXPORTSIZE :
1453 						   20);
1454 		}
1455 
1456 		j->close_ok = 1;
1457 		j->handshake_ok = 1;
1458 	}
1459 }
1460 
try_rehandshake(listener_item * j)1461 static void try_rehandshake(listener_item *j)
1462 {
1463 	int r, ret;
1464 	fprintf(stderr, "*** Received hello message\n");
1465 
1466 	do {
1467 		r = gnutls_handshake(j->tls_session);
1468 	} while (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN);
1469 
1470 	if (r < 0) {
1471 		do {
1472 			ret = gnutls_alert_send_appropriate(j->tls_session, r);
1473 		} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
1474 		fprintf(stderr, "Error in rehandshake: %s\n", gnutls_strerror(r));
1475 		j->http_state = HTTP_STATE_CLOSING;
1476 	} else {
1477 		j->close_ok = 1;
1478 		j->http_state = HTTP_STATE_REQUEST;
1479 	}
1480 }
1481 
tcp_server(const char * name,int port)1482 static void tcp_server(const char *name, int port)
1483 {
1484 	int n, s;
1485 	char topbuf[512];
1486 	int accept_fd;
1487 	struct sockaddr_storage client_address;
1488 	socklen_t calen;
1489 	struct timeval tv;
1490 
1491 	s = listen_socket(name, port, SOCK_STREAM);
1492 	if (s < 0)
1493 		exit(1);
1494 
1495 	for (;;) {
1496 		listener_item *j;
1497 		fd_set rd, wr;
1498 		time_t now = time(0);
1499 #ifndef _WIN32
1500 		int val;
1501 #endif
1502 
1503 		FD_ZERO(&rd);
1504 		FD_ZERO(&wr);
1505 		n = 0;
1506 
1507 /* flag which connections we are reading or writing to within the fd sets */
1508 		lloopstart(listener_list, j) {
1509 
1510 #ifndef _WIN32
1511 			val = fcntl(j->fd, F_GETFL, 0);
1512 			if ((val == -1)
1513 			    || (fcntl(j->fd, F_SETFL, val | O_NONBLOCK) <
1514 				0)) {
1515 				perror("fcntl()");
1516 				exit(1);
1517 			}
1518 #endif
1519 			if (j->start != 0 && now - j->start > 30) {
1520 				if (verbose != 0) {
1521 					fprintf(stderr, "Scheduling inactive connection for close\n");
1522 				}
1523 				j->http_state = HTTP_STATE_CLOSING;
1524 			}
1525 
1526 			if (j->listen_socket) {
1527 				FD_SET(j->fd, &rd);
1528 				n = MAX(n, j->fd);
1529 			}
1530 			if (j->http_state == HTTP_STATE_REQUEST) {
1531 				FD_SET(j->fd, &rd);
1532 				n = MAX(n, j->fd);
1533 			}
1534 			if (j->http_state == HTTP_STATE_RESPONSE) {
1535 				FD_SET(j->fd, &wr);
1536 				n = MAX(n, j->fd);
1537 			}
1538 		}
1539 		lloopend(listener_list, j);
1540 
1541 /* core operation */
1542 		tv.tv_sec = 10;
1543 		tv.tv_usec = 0;
1544 		n = select(n + 1, &rd, &wr, NULL, &tv);
1545 		if (n == -1 && errno == EINTR)
1546 			continue;
1547 		if (n < 0) {
1548 			perror("select()");
1549 			exit(1);
1550 		}
1551 
1552 /* read or write to each connection as indicated by select()'s return argument */
1553 		lloopstart(listener_list, j) {
1554 
1555 			/* a new connection has arrived */
1556 			if (FD_ISSET(j->fd, &rd) && j->listen_socket) {
1557 				calen = sizeof(client_address);
1558 				memset(&client_address, 0, calen);
1559 				accept_fd =
1560 				    accept(j->fd,
1561 					   (struct sockaddr *)
1562 					   &client_address, &calen);
1563 
1564 				if (accept_fd < 0) {
1565 					perror("accept()");
1566 				} else {
1567 					char timebuf[SIMPLE_CTIME_BUF_SIZE];
1568 					time_t tt = time(0);
1569 					char *ctt;
1570 
1571 					/* new list entry for the connection */
1572 					lappend(listener_list);
1573 					j = listener_list.tail;
1574 					j->http_request =
1575 					    (char *) strdup("");
1576 					j->http_state = HTTP_STATE_REQUEST;
1577 					j->fd = accept_fd;
1578 					j->start = tt;
1579 
1580 					j->tls_session = initialize_session(0);
1581 					gnutls_session_set_ptr(j->tls_session, j);
1582 					gnutls_transport_set_int
1583 					    (j->tls_session, accept_fd);
1584 					set_read_funcs(j->tls_session);
1585 					j->handshake_ok = 0;
1586 					j->close_ok = 0;
1587 
1588 					if (verbose != 0) {
1589 						ctt = simple_ctime(&tt, timebuf);
1590 						ctt[strlen(ctt) - 1] = 0;
1591 
1592 						printf
1593 						    ("\n* Accepted connection from %s on %s\n",
1594 						     human_addr((struct
1595 								 sockaddr
1596 								 *)
1597 								&client_address,
1598 								calen,
1599 								topbuf,
1600 								sizeof
1601 								(topbuf)),
1602 						     ctt);
1603 					}
1604 				}
1605 			}
1606 
1607 			if (FD_ISSET(j->fd, &rd) && !j->listen_socket) {
1608 /* read partial GET request */
1609 				char buf[16*1024];
1610 				int r;
1611 
1612 				if (j->handshake_ok == 0) {
1613 					retry_handshake(j);
1614 				}
1615 
1616 				if (j->handshake_ok == 1) {
1617 					int earlydata_read = 0;
1618 					if (earlydata && !j->earlydata_eof) {
1619 						r = gnutls_record_recv_early_data(j->
1620 										  tls_session,
1621 										  buf,
1622 										  MIN(sizeof(buf),
1623 										      SMALL_READ_TEST));
1624 						if (r == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1625 							j->earlydata_eof = 1;
1626 						}
1627 						if (r == 0) {
1628 							earlydata_read = 1;
1629 						}
1630 					}
1631 					if (!earlydata_read) {
1632 						r = gnutls_record_recv(j->
1633 								       tls_session,
1634 								       buf,
1635 								       MIN(sizeof(buf),
1636 									   SMALL_READ_TEST));
1637 					}
1638 					if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
1639 						/* do nothing */
1640 					} else if (r <= 0) {
1641 						if (r == GNUTLS_E_HEARTBEAT_PING_RECEIVED) {
1642 							gnutls_heartbeat_pong(j->tls_session, 0);
1643 						} else if (r == GNUTLS_E_REHANDSHAKE) {
1644 							try_rehandshake(j);
1645 						} else {
1646 							j->http_state = HTTP_STATE_CLOSING;
1647 							if (r < 0) {
1648 								int ret;
1649 								check_alert(j->tls_session, r);
1650 								fprintf(stderr,
1651 								     "Error while receiving data\n");
1652 								do {
1653 									ret = gnutls_alert_send_appropriate(j->tls_session, r);
1654 								} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
1655 								GERR(r);
1656 								j->close_ok = 0;
1657 							}
1658 						}
1659 					} else {
1660 						j->http_request =
1661 						    realloc(j->
1662 							    http_request,
1663 							    j->
1664 							    request_length
1665 							    + r + 1);
1666 						if (j->http_request !=
1667 						    NULL) {
1668 							memcpy(j->
1669 							       http_request
1670 							       +
1671 							       j->
1672 							       request_length,
1673 							       buf, r);
1674 							j->request_length
1675 							    += r;
1676 							j->http_request[j->
1677 									request_length]
1678 							    = '\0';
1679 						} else {
1680 							j->http_state =
1681 							    HTTP_STATE_CLOSING;
1682 						}
1683 					}
1684 /* check if we have a full HTTP header */
1685 
1686 					j->http_response = NULL;
1687 					if (j->http_state == HTTP_STATE_REQUEST && j->http_request != NULL) {
1688 						if ((http == 0
1689 						     && strchr(j->
1690 							       http_request,
1691 							       '\n'))
1692 						    || strstr(j->
1693 							      http_request,
1694 							      "\r\n\r\n")
1695 						    || strstr(j->
1696 							      http_request,
1697 							      "\n\n")) {
1698 							if (get_response(j->
1699 								         tls_session,
1700 								         j->
1701 								         http_request,
1702 								         &j->
1703 								         http_response,
1704 								         &j->
1705 								         response_length)) {
1706 								j->http_state =
1707 								    HTTP_STATE_RESPONSE;
1708 								j->response_written
1709 								    = 0;
1710 							} else {
1711 								j->http_state = HTTP_STATE_CLOSING;
1712 							}
1713 						}
1714 					}
1715 				}
1716 			}
1717 
1718 			if (FD_ISSET(j->fd, &wr)) {
1719 /* write partial response request */
1720 				int r;
1721 
1722 				if (j->handshake_ok == 0) {
1723 					retry_handshake(j);
1724 				}
1725 
1726 				if (j->handshake_ok == 1 && j->http_response == NULL) {
1727 					j->http_state = HTTP_STATE_CLOSING;
1728 				} else if (j->handshake_ok == 1 && j->http_response != NULL) {
1729 					r = gnutls_record_send(j->tls_session,
1730 							       j->http_response
1731 							       +
1732 							       j->response_written,
1733 							       MIN(j->response_length
1734 								   -
1735 								   j->response_written,
1736 								   SMALL_READ_TEST));
1737 					if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
1738 						/* do nothing */
1739 					} else if (r <= 0) {
1740 						j->http_state = HTTP_STATE_CLOSING;
1741 						if (r < 0) {
1742 							fprintf(stderr,
1743 								"Error while sending data\n");
1744 							GERR(r);
1745 						}
1746 						check_alert(j->tls_session,
1747 							    r);
1748 					} else {
1749 						j->response_written += r;
1750 /* check if we have written a complete response */
1751 						if (j->response_written ==
1752 						    j->response_length) {
1753 							if (http != 0)
1754 								j->http_state = HTTP_STATE_CLOSING;
1755 							else {
1756 								j->http_state = HTTP_STATE_REQUEST;
1757 								free(j->
1758 								     http_response);
1759 								j->http_response = NULL;
1760 								j->response_length = 0;
1761 								j->request_length = 0;
1762 								j->http_request[0] = 0;
1763 							}
1764 						}
1765 					}
1766 				} else {
1767 					j->request_length = 0;
1768 					j->http_request[0] = 0;
1769 					j->http_state = HTTP_STATE_REQUEST;
1770 				}
1771 			}
1772 		}
1773 		lloopend(listener_list, j);
1774 
1775 /* loop through all connections, closing those that are in error */
1776 		lloopstart(listener_list, j) {
1777 			if (j->http_state == HTTP_STATE_CLOSING) {
1778 				ldeleteinc(listener_list, j);
1779 			}
1780 		}
1781 		lloopend(listener_list, j);
1782 	}
1783 
1784 
1785 	gnutls_certificate_free_credentials(cert_cred);
1786 
1787 #ifdef ENABLE_SRP
1788 	if (srp_cred)
1789 		gnutls_srp_free_server_credentials(srp_cred);
1790 #endif
1791 
1792 #ifdef ENABLE_PSK
1793 	if (psk_cred)
1794 		gnutls_psk_free_server_credentials(psk_cred);
1795 #endif
1796 
1797 #ifdef ENABLE_ANON
1798 	gnutls_anon_free_server_credentials(dh_cred);
1799 #endif
1800 
1801 	if (noticket == 0)
1802 		gnutls_free(session_ticket_key.data);
1803 
1804 	if (earlydata)
1805 		gnutls_anti_replay_deinit(anti_replay);
1806 
1807 	if (nodb == 0)
1808 		wrap_db_deinit();
1809 	gnutls_global_deinit();
1810 
1811 }
1812 
cmd_parser(int argc,char ** argv)1813 static void cmd_parser(int argc, char **argv)
1814 {
1815 	optionProcess(&gnutls_servOptions, argc, argv);
1816 
1817 	disable_client_cert = HAVE_OPT(DISABLE_CLIENT_CERT);
1818 	require_cert = ENABLED_OPT(REQUIRE_CLIENT_CERT);
1819 	if (HAVE_OPT(DEBUG))
1820 		debug = OPT_VALUE_DEBUG;
1821 
1822 	if (HAVE_OPT(QUIET))
1823 		verbose = 0;
1824 
1825 	if (HAVE_OPT(PRIORITY))
1826 		priorities = OPT_ARG(PRIORITY);
1827 
1828 	if (HAVE_OPT(LIST)) {
1829 		print_list(priorities, verbose);
1830 		exit(0);
1831 	}
1832 
1833 	nodb = HAVE_OPT(NODB);
1834 	noticket = HAVE_OPT(NOTICKET);
1835 	earlydata = HAVE_OPT(EARLYDATA);
1836 
1837 	if (HAVE_OPT(ECHO))
1838 		http = 0;
1839 	else
1840 		http = 1;
1841 
1842 	record_max_size = OPT_VALUE_RECORDSIZE;
1843 
1844 	if (HAVE_OPT(X509FMTDER))
1845 		x509ctype = GNUTLS_X509_FMT_DER;
1846 	else
1847 		x509ctype = GNUTLS_X509_FMT_PEM;
1848 
1849 	generate = HAVE_OPT(GENERATE);
1850 
1851 	if (HAVE_OPT(DHPARAMS))
1852 		dh_params_file = OPT_ARG(DHPARAMS);
1853 
1854 	if (HAVE_OPT(ALPN)) {
1855 		alpn_protos = STACKLST_OPT(ALPN);
1856 		alpn_protos_size = STACKCT_OPT(ALPN);
1857 	}
1858 
1859 	if (HAVE_OPT(X509KEYFILE)) {
1860 		x509_keyfile = STACKLST_OPT(X509KEYFILE);
1861 		x509_keyfile_size = STACKCT_OPT(X509KEYFILE);
1862 	}
1863 
1864 	if (HAVE_OPT(X509CERTFILE)) {
1865 		x509_certfile = STACKLST_OPT(X509CERTFILE);
1866 		x509_certfile_size = STACKCT_OPT(X509CERTFILE);
1867 	}
1868 
1869 	if (x509_certfile_size != x509_keyfile_size) {
1870 		fprintf(stderr, "The certificate number provided (%u) doesn't match the keys (%u)\n",
1871 			x509_certfile_size, x509_keyfile_size);
1872 			exit(1);
1873 	}
1874 
1875 	if (HAVE_OPT(X509CAFILE))
1876 		x509_cafile = OPT_ARG(X509CAFILE);
1877 	if (HAVE_OPT(X509CRLFILE))
1878 		x509_crlfile = OPT_ARG(X509CRLFILE);
1879 
1880 	if (HAVE_OPT(RAWPKKEYFILE)) {
1881 		rawpk_keyfile = STACKLST_OPT(RAWPKKEYFILE);
1882 		rawpk_keyfile_size = STACKCT_OPT(RAWPKKEYFILE);
1883 	}
1884 
1885 	if (HAVE_OPT(RAWPKFILE)) {
1886 		rawpk_file = STACKLST_OPT(RAWPKFILE);
1887 		rawpk_file_size = STACKCT_OPT(RAWPKFILE);
1888 	}
1889 
1890 	if (rawpk_file_size != rawpk_keyfile_size) {
1891 		fprintf(stderr, "The number of raw public-keys provided (%u) doesn't match the number of corresponding private keys (%u)\n",
1892 			rawpk_file_size, rawpk_keyfile_size);
1893 			exit(1);
1894 	}
1895 
1896 	if (HAVE_OPT(SRPPASSWD))
1897 		srp_passwd = OPT_ARG(SRPPASSWD);
1898 	if (HAVE_OPT(SRPPASSWDCONF))
1899 		srp_passwd_conf = OPT_ARG(SRPPASSWDCONF);
1900 
1901 	if (HAVE_OPT(PSKPASSWD))
1902 		psk_passwd = OPT_ARG(PSKPASSWD);
1903 
1904 	if (HAVE_OPT(OCSP_RESPONSE)) {
1905 		ocsp_responses = STACKLST_OPT(OCSP_RESPONSE);
1906 		ocsp_responses_size = STACKCT_OPT(OCSP_RESPONSE);
1907 	}
1908 
1909 	if (HAVE_OPT(SNI_HOSTNAME))
1910 		sni_hostname = OPT_ARG(SNI_HOSTNAME);
1911 
1912 	if (HAVE_OPT(SNI_HOSTNAME_FATAL))
1913 		sni_hostname_fatal = 1;
1914 
1915 	if (HAVE_OPT(HTTPDATA))
1916 		http_data_file = OPT_ARG(HTTPDATA);
1917 
1918 }
1919 
1920 /* session resuming support */
1921 
1922 #define SESSION_ID_SIZE 128
1923 #define SESSION_DATA_SIZE (16*1024)
1924 
1925 typedef struct {
1926 	unsigned char session_id[SESSION_ID_SIZE];
1927 	unsigned int session_id_size;
1928 
1929 	gnutls_datum_t session_data;
1930 } CACHE;
1931 
1932 static CACHE *cache_db;
1933 static int cache_db_ptr;
1934 static int cache_db_alloc;
1935 
wrap_db_init(void)1936 static void wrap_db_init(void)
1937 {
1938 }
1939 
wrap_db_deinit(void)1940 static void wrap_db_deinit(void)
1941 {
1942 	int i;
1943 
1944 	for (i = 0; i < cache_db_ptr; i++)
1945 		free(cache_db[i].session_data.data);
1946 	free(cache_db);
1947 }
1948 
1949 static int
wrap_db_store(void * dbf,gnutls_datum_t key,gnutls_datum_t data)1950 wrap_db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1951 {
1952 	int i;
1953 	time_t now = time(0);
1954 
1955 	if (key.size > SESSION_ID_SIZE)
1956 		return GNUTLS_E_DB_ERROR;
1957 	if (data.size > SESSION_DATA_SIZE)
1958 		return GNUTLS_E_DB_ERROR;
1959 
1960 	if (cache_db_ptr < cache_db_alloc)
1961 		i = cache_db_ptr++;
1962 	else {
1963 		/* find empty or expired slot to store the new entry */
1964 		for (i = 0; i < cache_db_ptr; i++)
1965 			if (cache_db[i].session_id_size == 0 ||
1966 			    !(now <
1967 			      gnutls_db_check_entry_expire_time(&cache_db[i].
1968 								session_data)))
1969 				break;
1970 
1971 		if (i == cache_db_ptr) {
1972 			/* try to allocate additional slots */
1973 			if (cache_db_ptr == ssl_session_cache) {
1974 				fprintf(stderr,
1975 					"Error: too many sessions\n");
1976 				return GNUTLS_E_DB_ERROR;
1977 			}
1978 			cache_db_alloc = cache_db_alloc * 2 + 1;
1979 			cache_db = realloc(cache_db,
1980 					   cache_db_alloc * sizeof(CACHE));
1981 			if (!cache_db)
1982 				return GNUTLS_E_MEMORY_ERROR;
1983 			memset(cache_db + cache_db_ptr, 0,
1984 			       (cache_db_alloc - cache_db_ptr) * sizeof(CACHE));
1985 			cache_db_ptr++;
1986 		}
1987 	}
1988 
1989 	memcpy(cache_db[i].session_id, key.data, key.size);
1990 	cache_db[i].session_id_size = key.size;
1991 
1992 	/* resize the data slot if needed */
1993 	if (cache_db[i].session_data.size < data.size) {
1994 		cache_db[i].session_data.data =
1995 			realloc(cache_db[i].session_data.data,
1996 				data.size);
1997 		if (!cache_db[i].session_data.data)
1998 			return GNUTLS_E_MEMORY_ERROR;
1999 	}
2000 	memcpy(cache_db[i].session_data.data, data.data, data.size);
2001 	cache_db[i].session_data.size = data.size;
2002 
2003 	return 0;
2004 }
2005 
wrap_db_fetch(void * dbf,gnutls_datum_t key)2006 static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key)
2007 {
2008 	gnutls_datum_t res = { NULL, 0 };
2009 	time_t now = time(0);
2010 	int i;
2011 
2012 	for (i = 0; i < cache_db_ptr; i++) {
2013 		if (key.size == cache_db[i].session_id_size &&
2014 		    memcmp(key.data, cache_db[i].session_id,
2015 			   key.size) == 0 &&
2016 		    now < gnutls_db_check_entry_expire_time(&cache_db[i].
2017 							    session_data)) {
2018 			res.size = cache_db[i].session_data.size;
2019 
2020 			res.data = malloc(res.size);
2021 			if (res.data == NULL)
2022 				return res;
2023 
2024 			memcpy(res.data, cache_db[i].session_data.data,
2025 			       res.size);
2026 
2027 			return res;
2028 		}
2029 	}
2030 	return res;
2031 }
2032 
wrap_db_delete(void * dbf,gnutls_datum_t key)2033 static int wrap_db_delete(void *dbf, gnutls_datum_t key)
2034 {
2035 	int i;
2036 
2037 	for (i = 0; i < cache_db_ptr; i++) {
2038 		if (key.size == cache_db[i].session_id_size &&
2039 		    memcmp(key.data, cache_db[i].session_id,
2040 			   key.size) == 0) {
2041 
2042 			cache_db[i].session_id_size = 0;
2043 			free(cache_db[i].session_data.data);
2044 			cache_db[i].session_data.data = NULL;
2045 			cache_db[i].session_data.size = 0;
2046 
2047 			return 0;
2048 		}
2049 	}
2050 
2051 	return GNUTLS_E_DB_ERROR;
2052 }
2053 
2054 static int
anti_replay_db_add(void * dbf,time_t exp,const gnutls_datum_t * key,const gnutls_datum_t * data)2055 anti_replay_db_add(void *dbf, time_t exp, const gnutls_datum_t *key, const gnutls_datum_t *data)
2056 {
2057 	time_t now = time(0);
2058 	int i;
2059 
2060 	for (i = 0; i < cache_db_ptr; i++) {
2061 		if (key->size == cache_db[i].session_id_size &&
2062 		    memcmp(key->data, cache_db[i].session_id,
2063 			   key->size) == 0 &&
2064 		    now < gnutls_db_check_entry_expire_time(&cache_db[i].
2065 							    session_data))
2066 			return GNUTLS_E_DB_ENTRY_EXISTS;
2067 	}
2068 
2069 	return wrap_db_store(dbf, *key, *data);
2070 }
2071