documented updates
[gnutls.git] / src / serv.c
blob26b669961aaca49c9210a6f7f31302692bd11ae2
1 /*
2 * Copyright (C) 2004-2012 Free Software Foundation, Inc.
3 * Copyright (C) 2001,2002 Paul Sheer
4 * Portions Copyright (C) 2002,2003 Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * GnuTLS is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * GnuTLS is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* This server is heavily modified for GnuTLS by Nikos Mavrogiannopoulos
23 * (which means it is quite unreadable)
26 #include <config.h>
28 #include "common.h"
29 #include "serv-args.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <string.h>
35 #include <gnutls/gnutls.h>
36 #include <gnutls/dtls.h>
37 #include <gnutls/openpgp.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>
46 /* Gnulib portability files. */
47 #include "progname.h"
48 #include "version-etc.h"
49 #include "read-file.h"
50 #include "minmax.h"
51 #include "sockets.h"
52 #include "udp-serv.h"
54 /* konqueror cannot handle sending the page in multiple
55 * pieces.
57 /* global stuff */
58 static int generate = 0;
59 static int http = 0;
60 static int x509ctype;
61 static int debug = 0;
63 unsigned int verbose = 1;
64 static int nodb;
65 static int noticket;
66 int require_cert;
67 int disable_client_cert;
69 const char *psk_passwd = NULL;
70 const char *srp_passwd = NULL;
71 const char *srp_passwd_conf = NULL;
72 const char *pgp_keyring = NULL;
73 const char *pgp_keyfile = NULL;
74 const char *pgp_certfile = NULL;
75 const char *x509_keyfile = NULL;
76 const char *x509_certfile = NULL;
77 const char *x509_dsakeyfile = NULL;
78 const char *x509_dsacertfile = NULL;
79 const char *x509_ecckeyfile = NULL;
80 const char *x509_ecccertfile = NULL;
81 const char *x509_cafile = NULL;
82 const char *dh_params_file = NULL;
83 const char *x509_crlfile = NULL;
84 const char * priorities = NULL;
85 const char * status_response_ocsp = NULL;
87 gnutls_datum_t session_ticket_key;
88 static void tcp_server (const char *name, int port);
90 /* end of globals */
92 /* This is a sample TCP echo server.
93 * This will behave as an http server if any argument in the
94 * command line is present
97 #define SMALL_READ_TEST (2147483647)
99 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
101 #define HTTP_END "</BODY></HTML>\n\n"
103 #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"
104 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
106 #define HTTP_BEGIN HTTP_OK \
107 "\n" \
108 "<HTML><BODY>\n" \
109 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
110 "GnuTLS</a></H1></CENTER>\n\n"
112 /* These are global */
113 gnutls_srp_server_credentials_t srp_cred = NULL;
114 gnutls_psk_server_credentials_t psk_cred = NULL;
115 gnutls_anon_server_credentials_t dh_cred = NULL;
116 gnutls_certificate_credentials_t cert_cred = NULL;
118 const int ssl_session_cache = 128;
120 static void wrap_db_init (void);
121 static void wrap_db_deinit (void);
122 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
123 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
124 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
126 static void cmd_parser (int argc, char **argv);
129 #define HTTP_STATE_REQUEST 1
130 #define HTTP_STATE_RESPONSE 2
131 #define HTTP_STATE_CLOSING 3
133 LIST_TYPE_DECLARE (listener_item, char *http_request;
134 char *http_response; int request_length;
135 int response_length; int response_written;
136 int http_state; int listen_socket;
137 int fd; gnutls_session_t tls_session; int handshake_ok;);
139 static const char *
140 safe_strerror (int value)
142 const char *ret = gnutls_strerror (value);
143 if (ret == NULL)
144 ret = str_unknown;
145 return ret;
148 static void
149 listener_free (listener_item * j)
152 free (j->http_request);
153 free (j->http_response);
154 if (j->fd >= 0)
156 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
157 shutdown (j->fd, 2);
158 close (j->fd);
159 gnutls_deinit (j->tls_session);
164 /* we use primes up to 1024 in this server.
165 * otherwise we should add them here.
168 gnutls_dh_params_t dh_params = NULL;
169 gnutls_rsa_params_t rsa_params = NULL;
171 static int
172 generate_dh_primes (void)
174 int prime_bits =
175 gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL);
177 if (gnutls_dh_params_init (&dh_params) < 0)
179 fprintf (stderr, "Error in dh parameter initialization\n");
180 exit (1);
183 /* Generate Diffie-Hellman parameters - for use with DHE
184 * kx algorithms. These should be discarded and regenerated
185 * once a week or once a month. Depends on the
186 * security requirements.
188 printf
189 ("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
190 prime_bits);
191 fflush (stdout);
193 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
195 fprintf (stderr, "Error in prime generation\n");
196 exit (1);
199 return 0;
202 static void
203 read_dh_params (void)
205 char tmpdata[2048];
206 int size;
207 gnutls_datum_t params;
208 FILE *fd;
210 if (gnutls_dh_params_init (&dh_params) < 0)
212 fprintf (stderr, "Error in dh parameter initialization\n");
213 exit (1);
216 /* read the params file
218 fd = fopen (dh_params_file, "r");
219 if (fd == NULL)
221 fprintf (stderr, "Could not open %s\n", dh_params_file);
222 exit (1);
225 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
226 tmpdata[size] = 0;
227 fclose (fd);
229 params.data = (unsigned char *) tmpdata;
230 params.size = size;
232 size =
233 gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
235 if (size < 0)
237 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
238 exit (1);
241 printf ("Read Diffie-Hellman parameters.\n");
242 fflush (stdout);
246 static char pkcs3[] =
247 "-----BEGIN DH PARAMETERS-----\n"
248 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
249 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
250 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
251 "-----END DH PARAMETERS-----\n";
253 static int
254 static_dh_params (void)
256 gnutls_datum_t params = { (void *) pkcs3, sizeof (pkcs3) };
257 int ret;
259 if (gnutls_dh_params_init (&dh_params) < 0)
261 fprintf (stderr, "Error in dh parameter initialization\n");
262 exit (1);
265 ret = gnutls_dh_params_import_pkcs3 (dh_params, &params,
266 GNUTLS_X509_FMT_PEM);
268 if (ret < 0)
270 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
271 exit (1);
274 printf ("Set static Diffie-Hellman parameters, consider --dhparams.\n");
276 return 0;
279 static int
280 get_params (gnutls_session_t session, gnutls_params_type_t type,
281 gnutls_params_st * st)
284 if (type == GNUTLS_PARAMS_RSA_EXPORT)
286 if (rsa_params == NULL)
287 return -1;
288 st->params.rsa_export = rsa_params;
290 else if (type == GNUTLS_PARAMS_DH)
292 if (dh_params == NULL)
293 return -1;
294 st->params.dh = dh_params;
296 else
297 return -1;
299 st->type = type;
300 st->deinit = 0;
302 return 0;
305 static int
306 generate_rsa_params (void)
308 if (gnutls_rsa_params_init (&rsa_params) < 0)
310 fprintf (stderr, "Error in rsa parameter initialization\n");
311 exit (1);
314 /* Generate RSA parameters - for use with RSA-export
315 * cipher suites. These should be discarded and regenerated
316 * once a day, once every 500 transactions etc. Depends on the
317 * security requirements.
319 printf ("Generating temporary RSA parameters. Please wait...\n");
320 fflush (stdout);
322 if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
324 fprintf (stderr, "Error in rsa parameter generation\n");
325 exit (1);
328 return 0;
331 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
333 gnutls_session_t initialize_session (int dtls)
335 gnutls_session_t session;
336 const char *err;
338 if (priorities == NULL)
339 priorities = "NORMAL";
341 if (dtls)
342 gnutls_init (&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
343 else
344 gnutls_init (&session, GNUTLS_SERVER);
346 /* allow the use of private ciphersuites.
348 gnutls_handshake_set_private_extensions (session, 1);
350 if (nodb == 0)
352 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
353 gnutls_db_set_remove_function (session, wrap_db_delete);
354 gnutls_db_set_store_function (session, wrap_db_store);
355 gnutls_db_set_ptr (session, NULL);
357 #ifdef ENABLE_SESSION_TICKET
358 if (noticket == 0)
359 gnutls_session_ticket_enable_server (session, &session_ticket_key);
360 #endif
362 /* OCSP status-request TLS extension */
363 if (status_response_ocsp)
365 if (gnutls_status_request_ocsp_server_file (session, status_response_ocsp, 0) < 0)
367 fprintf (stderr, "Cannot set OCSP status request callback.\n");
368 exit (1);
372 if (noticket == 0)
373 gnutls_session_ticket_enable_server (session, &session_ticket_key);
375 if (gnutls_priority_set_direct (session, priorities, &err) < 0)
377 fprintf (stderr, "Syntax error at: %s\n", err);
378 exit (1);
381 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
383 if (srp_cred != NULL)
384 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
386 if (psk_cred != NULL)
387 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
389 if (cert_cred != NULL)
390 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
392 if (disable_client_cert)
393 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
394 else
396 if (require_cert)
397 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
398 else
399 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
402 if (HAVE_OPT (HEARTBEAT))
403 gnutls_heartbeat_enable(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND);
405 return session;
408 #include <gnutls/x509.h>
410 static const char DEFAULT_DATA[] =
411 "This is the default message reported by the GnuTLS implementation. "
412 "For more information please visit "
413 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
415 /* Creates html with the current session information.
417 #define tmp_buffer &http_buffer[strlen(http_buffer)]
418 #define tmp_buffer_size len-strlen(http_buffer)
419 static char *
420 peer_print_info (gnutls_session_t session, int *ret_length,
421 const char *header)
423 const char *tmp;
424 unsigned char sesid[32];
425 size_t i, sesid_size;
426 char *http_buffer;
427 gnutls_kx_algorithm_t kx_alg;
428 size_t len = 20 * 1024 + strlen (header);
429 char *crtinfo = NULL;
430 size_t ncrtinfo = 0;
432 if (verbose == 0)
434 http_buffer = malloc (len);
435 if (http_buffer == NULL)
436 return NULL;
438 strcpy (http_buffer, HTTP_BEGIN);
439 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
440 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
441 HTTP_END);
442 *ret_length =
443 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
444 return http_buffer;
447 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
449 const gnutls_datum_t *cert_list;
450 unsigned int cert_list_size = 0;
452 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
454 for (i = 0; i < cert_list_size; i++)
456 gnutls_x509_crt_t cert;
457 gnutls_datum_t info;
459 if (gnutls_x509_crt_init (&cert) == 0 &&
460 gnutls_x509_crt_import (cert, &cert_list[i],
461 GNUTLS_X509_FMT_DER) == 0 &&
462 gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &info) == 0)
464 const char *post = "</PRE><P><PRE>";
466 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
467 strlen (post) + 1);
468 if (crtinfo == NULL)
469 return NULL;
470 memcpy (crtinfo + ncrtinfo, info.data, info.size);
471 ncrtinfo += info.size;
472 memcpy (crtinfo + ncrtinfo, post, strlen (post));
473 ncrtinfo += strlen (post);
474 crtinfo[ncrtinfo] = '\0';
475 gnutls_free (info.data);
480 http_buffer = malloc (len);
481 if (http_buffer == NULL)
483 free (crtinfo);
484 return NULL;
487 strcpy (http_buffer, HTTP_BEGIN);
489 /* print session_id */
490 sesid_size = sizeof(sesid);
491 gnutls_session_get_id (session, sesid, &sesid_size);
492 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Session ID: <i>");
493 for (i = 0; i < sesid_size; i++)
494 snprintf (tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
495 snprintf (tmp_buffer, tmp_buffer_size, "</i></p>\n");
496 snprintf (tmp_buffer, tmp_buffer_size,
497 "<h5>If your browser supports session resuming, then you should see the "
498 "same session ID, when you press the <b>reload</b> button.</h5>\n");
500 /* Here unlike print_info() we use the kx algorithm to distinguish
501 * the functions to call.
504 char dns[256];
505 size_t dns_size = sizeof (dns);
506 unsigned int type;
508 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
510 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Server Name: %s</p>\n",
511 dns);
516 kx_alg = gnutls_kx_get (session);
518 /* print srp specific data */
519 #ifdef ENABLE_SRP
520 if (kx_alg == GNUTLS_KX_SRP)
522 snprintf (tmp_buffer, tmp_buffer_size,
523 "<p>Connected as user '%s'.</p>\n",
524 gnutls_srp_server_get_username (session));
526 #endif
528 #ifdef ENABLE_PSK
529 if (kx_alg == GNUTLS_KX_PSK)
531 snprintf (tmp_buffer, tmp_buffer_size,
532 "<p>Connected as user '%s'.</p>\n",
533 gnutls_psk_server_get_username (session));
535 #endif
537 #ifdef ENABLE_ANON
538 if (kx_alg == GNUTLS_KX_ANON_DH)
540 snprintf (tmp_buffer, tmp_buffer_size,
541 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
542 gnutls_dh_get_prime_bits (session));
544 #endif
546 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
548 snprintf (tmp_buffer, tmp_buffer_size,
549 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
550 gnutls_dh_get_prime_bits (session));
553 /* print session information */
554 strcat (http_buffer, "<P>\n");
556 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
557 if (tmp == NULL)
558 tmp = str_unknown;
559 snprintf (tmp_buffer, tmp_buffer_size,
560 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
561 tmp);
563 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
565 tmp =
566 gnutls_certificate_type_get_name (gnutls_certificate_type_get
567 (session));
568 if (tmp == NULL)
569 tmp = str_unknown;
570 snprintf (tmp_buffer, tmp_buffer_size,
571 "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
574 tmp = gnutls_kx_get_name (kx_alg);
575 if (tmp == NULL)
576 tmp = str_unknown;
577 snprintf (tmp_buffer, tmp_buffer_size,
578 "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
580 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
581 if (tmp == NULL)
582 tmp = str_unknown;
583 snprintf (tmp_buffer, tmp_buffer_size,
584 "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
586 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
587 if (tmp == NULL)
588 tmp = str_unknown;
589 snprintf (tmp_buffer, tmp_buffer_size,
590 "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
592 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
593 if (tmp == NULL)
594 tmp = str_unknown;
595 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n",
596 tmp);
598 tmp = gnutls_cipher_suite_get_name (kx_alg,
599 gnutls_cipher_get (session),
600 gnutls_mac_get (session));
601 if (tmp == NULL)
602 tmp = str_unknown;
603 snprintf (tmp_buffer, tmp_buffer_size,
604 "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n", tmp);
606 if (crtinfo)
608 snprintf (tmp_buffer, tmp_buffer_size, "<hr><PRE>%s\n</PRE>\n",
609 crtinfo);
610 free (crtinfo);
613 snprintf (tmp_buffer, tmp_buffer_size,
614 "<hr><P>Your HTTP header was:<PRE>%s</PRE></P>\n" HTTP_END,
615 header);
617 *ret_length = strlen (http_buffer);
619 return http_buffer;
622 const char *
623 human_addr (const struct sockaddr *sa, socklen_t salen,
624 char *buf, size_t buflen)
626 const char *save_buf = buf;
627 size_t l;
629 if (!buf || !buflen)
630 return NULL;
632 *buf = '\0';
634 switch (sa->sa_family)
636 #if HAVE_IPV6
637 case AF_INET6:
638 snprintf (buf, buflen, "IPv6 ");
639 break;
640 #endif
642 case AF_INET:
643 snprintf (buf, buflen, "IPv4 ");
644 break;
647 l = strlen (buf);
648 buf += l;
649 buflen -= l;
651 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
652 return NULL;
654 l = strlen (buf);
655 buf += l;
656 buflen -= l;
658 strncat (buf, " port ", buflen);
660 l = strlen (buf);
661 buf += l;
662 buflen -= l;
664 if (getnameinfo (sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
665 return NULL;
667 return save_buf;
671 wait_for_connection (void)
673 listener_item *j;
674 fd_set rd, wr;
675 int n, sock = -1;
677 FD_ZERO (&rd);
678 FD_ZERO (&wr);
679 n = 0;
681 lloopstart (listener_list, j)
683 if (j->listen_socket)
685 FD_SET (j->fd, &rd);
686 n = MAX (n, j->fd);
689 lloopend (listener_list, j);
691 /* waiting part */
692 n = select (n + 1, &rd, &wr, NULL, NULL);
693 if (n == -1 && errno == EINTR)
694 return -1;
695 if (n < 0)
697 perror ("select()");
698 exit (1);
701 /* find which one is ready */
702 lloopstart (listener_list, j)
704 /* a new connection has arrived */
705 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
707 sock = j->fd;
708 break;
711 lloopend (listener_list, j);
712 return sock;
716 listen_socket (const char *name, int listen_port, int socktype)
718 struct addrinfo hints, *res, *ptr;
719 char portname[6];
720 int s;
721 int yes;
722 listener_item *j = NULL;
724 snprintf (portname, sizeof (portname), "%d", listen_port);
725 memset (&hints, 0, sizeof (hints));
726 hints.ai_socktype = socktype;
727 hints.ai_flags = AI_PASSIVE
728 #ifdef AI_ADDRCONFIG
729 | AI_ADDRCONFIG
730 #endif
733 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
735 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
736 return -1;
739 for (ptr = res; ptr != NULL; ptr = ptr->ai_next)
741 #ifndef HAVE_IPV6
742 if (ptr->ai_family != AF_INET)
743 continue;
744 #endif
746 /* Print what we are doing. */
748 char topbuf[512];
750 fprintf (stderr, "%s listening on %s...",
751 name, human_addr (ptr->ai_addr, ptr->ai_addrlen,
752 topbuf, sizeof (topbuf)));
755 if ((s = socket (ptr->ai_family, ptr->ai_socktype,
756 ptr->ai_protocol)) < 0)
758 perror ("socket() failed");
759 continue;
762 #if defined(HAVE_IPV6) && !defined(_WIN32)
763 if (ptr->ai_family == AF_INET6)
765 yes = 1;
766 /* avoid listen on ipv6 addresses failing
767 * because already listening on ipv4 addresses: */
768 setsockopt (s, IPPROTO_IPV6, IPV6_V6ONLY,
769 (const void *) &yes, sizeof (yes));
771 #endif
773 if (socktype == SOCK_STREAM)
775 yes = 1;
776 if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
777 (const void *) &yes, sizeof (yes)) < 0)
779 perror ("setsockopt() failed");
780 close (s);
781 continue;
784 else
786 #if defined(IP_DONTFRAG)
787 yes = 1;
788 if (setsockopt (s, IPPROTO_IP, IP_DONTFRAG,
789 (const void *) &yes, sizeof (yes)) < 0)
790 perror ("setsockopt(IP_DF) failed");
791 #elif defined(IP_MTU_DISCOVER)
792 yes = IP_PMTUDISC_DO;
793 if (setsockopt (s, IPPROTO_IP, IP_MTU_DISCOVER,
794 (const void *) &yes, sizeof (yes)) < 0)
795 perror ("setsockopt(IP_DF) failed");
796 #endif
799 if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
801 perror ("bind() failed");
802 close (s);
803 continue;
806 if (socktype == SOCK_STREAM)
808 if (listen (s, 10) < 0)
810 perror ("listen() failed");
811 exit (1);
815 /* new list entry for the connection */
816 lappend (listener_list);
817 j = listener_list.tail;
818 j->listen_socket = 1;
819 j->fd = s;
821 /* Complete earlier message. */
822 fprintf (stderr, "done\n");
825 fflush (stderr);
827 freeaddrinfo (res);
829 return s;
832 /* strips \r\n from the end of the string
834 static void
835 strip (char *data)
837 int i;
838 int len = strlen (data);
840 for (i = 0; i < len; i++)
842 if (data[i] == '\r' && data[i + 1] == '\n' && data[i + 1] == 0)
844 data[i] = '\n';
845 data[i + 1] = 0;
846 break;
851 static void
852 get_response (gnutls_session_t session, char *request,
853 char **response, int *response_length)
855 char *p, *h;
857 if (http != 0)
859 if (strncmp (request, "GET ", 4))
860 goto unimplemented;
862 if (!(h = strchr (request, '\n')))
863 goto unimplemented;
865 *h++ = '\0';
866 while (*h == '\r' || *h == '\n')
867 h++;
869 if (!(p = strchr (request + 4, ' ')))
870 goto unimplemented;
871 *p = '\0';
873 /* *response = peer_print_info(session, request+4, h, response_length); */
874 if (http != 0)
876 *response = peer_print_info (session, response_length, h);
878 else
880 strip (request);
881 fprintf (stderr, "received: %s\n", request);
882 if (check_command (session, request))
884 *response = NULL;
885 *response_length = 0;
886 return;
888 *response = strdup (request);
889 *response_length = ((*response) ? strlen (*response) : 0);
892 return;
894 unimplemented:
895 *response = strdup (HTTP_UNIMPLEMENTED);
896 *response_length = ((*response) ? strlen (*response) : 0);
899 static void terminate (int sig) __attribute__ ((noreturn));
901 static void
902 terminate (int sig)
904 fprintf (stderr, "Exiting via signal %d\n", sig);
905 exit (1);
909 static void
910 check_alert (gnutls_session_t session, int ret)
912 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
913 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
915 int last_alert = gnutls_alert_get (session);
916 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
917 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
918 printf
919 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
920 else
921 printf ("* Received alert '%d': %s.\n", last_alert,
922 gnutls_alert_get_name (last_alert));
926 static void
927 tls_log_func (int level, const char *str)
929 fprintf (stderr, "|<%d>| %s", level, str);
932 static void
933 tls_audit_log_func (gnutls_session_t session, const char *str)
935 fprintf (stderr, "|<%p>| %s", session, str);
939 main (int argc, char **argv)
941 int ret, mtu, port;
942 char name[256];
944 set_program_name (argv[0]);
945 cmd_parser (argc, argv);
947 #ifndef _WIN32
948 signal (SIGHUP, SIG_IGN);
949 signal (SIGTERM, terminate);
950 if (signal (SIGINT, terminate) == SIG_IGN)
951 signal (SIGINT, SIG_IGN); /* e.g. background process */
952 #endif
954 sockets_init ();
956 if (nodb == 0)
957 wrap_db_init ();
959 if (HAVE_OPT (UDP))
960 strcpy (name, "UDP ");
961 else
962 name[0] = 0;
964 if (http == 1)
966 strcat (name, "HTTP Server");
968 else
970 strcat (name, "Echo Server");
973 gnutls_global_set_log_function (tls_log_func);
974 gnutls_global_set_audit_log_function (tls_audit_log_func);
975 gnutls_global_set_log_level (debug);
977 if ((ret = gnutls_global_init ()) < 0)
979 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
980 exit (1);
983 #ifdef ENABLE_PKCS11
984 pkcs11_common ();
985 #endif
987 /* Note that servers must generate parameters for
988 * Diffie-Hellman. See gnutls_dh_params_generate(), and
989 * gnutls_dh_params_set().
991 if (generate != 0)
993 generate_rsa_params ();
994 generate_dh_primes ();
996 else if (dh_params_file)
998 read_dh_params ();
1000 else
1002 static_dh_params ();
1005 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
1007 fprintf (stderr, "memory error\n");
1008 exit (1);
1011 if (x509_cafile != NULL)
1013 if ((ret = gnutls_certificate_set_x509_trust_file
1014 (cert_cred, x509_cafile, x509ctype)) < 0)
1016 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
1017 GERR (ret);
1018 exit (1);
1020 else
1022 printf ("Processed %d CA certificate(s).\n", ret);
1025 if (x509_crlfile != NULL)
1027 if ((ret = gnutls_certificate_set_x509_crl_file
1028 (cert_cred, x509_crlfile, x509ctype)) < 0)
1030 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
1031 GERR (ret);
1032 exit (1);
1034 else
1036 printf ("Processed %d CRL(s).\n", ret);
1040 #ifdef ENABLE_OPENPGP
1041 if (pgp_keyring != NULL)
1043 ret =
1044 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring,
1045 GNUTLS_OPENPGP_FMT_BASE64);
1046 if (ret < 0)
1048 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
1049 GERR (ret);
1053 if (HAVE_OPT (PGPCERTFILE))
1055 if (HAVE_OPT (PGPSUBKEY))
1056 ret = gnutls_certificate_set_openpgp_key_file2
1057 (cert_cred, pgp_certfile, pgp_keyfile, OPT_ARG (PGPSUBKEY),
1058 GNUTLS_OPENPGP_FMT_BASE64);
1059 else
1060 ret = gnutls_certificate_set_openpgp_key_file
1061 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64);
1063 if (ret < 0)
1065 fprintf (stderr,
1066 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1067 ret, pgp_certfile, pgp_keyfile);
1068 GERR (ret);
1071 #endif
1073 if (x509_certfile != NULL)
1074 if ((ret = gnutls_certificate_set_x509_key_file
1075 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
1077 fprintf (stderr,
1078 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1079 GERR (ret);
1080 exit (1);
1083 if (x509_dsacertfile != NULL)
1084 if ((ret = gnutls_certificate_set_x509_key_file
1085 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1087 fprintf (stderr, "Error reading '%s' or '%s'\n",
1088 x509_dsacertfile, x509_dsakeyfile);
1089 GERR (ret);
1090 exit (1);
1093 if (x509_ecccertfile != NULL)
1094 if ((ret = gnutls_certificate_set_x509_key_file
1095 (cert_cred, x509_ecccertfile, x509_ecckeyfile, x509ctype)) < 0)
1097 fprintf (stderr, "Error reading '%s' or '%s'\n",
1098 x509_ecccertfile, x509_ecckeyfile);
1099 GERR (ret);
1100 exit (1);
1103 gnutls_certificate_set_params_function (cert_cred, get_params);
1104 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1105 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1108 /* this is a password file (created with the included srpcrypt utility)
1109 * Read README.crypt prior to using SRP.
1111 #ifdef ENABLE_SRP
1112 if (srp_passwd != NULL)
1114 gnutls_srp_allocate_server_credentials (&srp_cred);
1116 if ((ret =
1117 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1118 srp_passwd_conf)) < 0)
1120 /* only exit is this function is not disabled
1122 fprintf (stderr, "Error while setting SRP parameters\n");
1123 GERR (ret);
1126 #endif
1128 /* this is a password file
1130 #ifdef ENABLE_PSK
1131 if (psk_passwd != NULL)
1133 gnutls_psk_allocate_server_credentials (&psk_cred);
1135 if ((ret =
1136 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1138 /* only exit is this function is not disabled
1140 fprintf (stderr, "Error while setting PSK parameters\n");
1141 GERR (ret);
1144 if (HAVE_OPT (PSKHINT))
1146 ret = gnutls_psk_set_server_credentials_hint (psk_cred,
1147 OPT_ARG (PSKHINT));
1148 if (ret)
1150 fprintf (stderr, "Error setting PSK identity hint.\n");
1151 GERR (ret);
1155 gnutls_psk_set_server_params_function (psk_cred, get_params);
1157 #endif
1159 #ifdef ENABLE_ANON
1160 gnutls_anon_allocate_server_credentials (&dh_cred);
1161 gnutls_anon_set_server_params_function (dh_cred, get_params);
1163 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1164 #endif
1166 #ifdef ENABLE_SESSION_TICKET
1167 if (noticket == 0)
1168 gnutls_session_ticket_key_generate (&session_ticket_key);
1169 #endif
1171 if (HAVE_OPT (MTU))
1172 mtu = OPT_VALUE_MTU;
1173 else
1174 mtu = 1300;
1176 if (HAVE_OPT (PORT))
1177 port = OPT_VALUE_PORT;
1178 else
1179 port = 5556;
1181 if (HAVE_OPT (UDP))
1182 udp_server (name, port, mtu);
1183 else
1184 tcp_server (name, port);
1187 static void
1188 tcp_server (const char *name, int port)
1190 int n, s;
1191 char topbuf[512];
1192 int accept_fd;
1193 struct sockaddr_storage client_address;
1194 socklen_t calen;
1196 s = listen_socket (name, port, SOCK_STREAM);
1197 if (s < 0)
1198 exit (1);
1200 for (;;)
1202 listener_item *j;
1203 fd_set rd, wr;
1204 #ifndef _WIN32
1205 int val;
1206 #endif
1208 FD_ZERO (&rd);
1209 FD_ZERO (&wr);
1210 n = 0;
1212 /* flag which connections we are reading or writing to within the fd sets */
1213 lloopstart (listener_list, j)
1216 #ifndef _WIN32
1217 val = fcntl (j->fd, F_GETFL, 0);
1218 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1220 perror ("fcntl()");
1221 exit (1);
1223 #endif
1225 if (j->listen_socket)
1227 FD_SET (j->fd, &rd);
1228 n = MAX (n, j->fd);
1230 if (j->http_state == HTTP_STATE_REQUEST)
1232 FD_SET (j->fd, &rd);
1233 n = MAX (n, j->fd);
1235 if (j->http_state == HTTP_STATE_RESPONSE)
1237 FD_SET (j->fd, &wr);
1238 n = MAX (n, j->fd);
1241 lloopend (listener_list, j);
1243 /* core operation */
1244 n = select (n + 1, &rd, &wr, NULL, NULL);
1245 if (n == -1 && errno == EINTR)
1246 continue;
1247 if (n < 0)
1249 perror ("select()");
1250 exit (1);
1253 /* read or write to each connection as indicated by select()'s return argument */
1254 lloopstart (listener_list, j)
1257 /* a new connection has arrived */
1258 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
1260 gnutls_session_t tls_session;
1262 tls_session = initialize_session (0);
1264 calen = sizeof (client_address);
1265 memset (&client_address, 0, calen);
1266 accept_fd = accept (j->fd, (struct sockaddr *) &client_address,
1267 &calen);
1269 if (accept_fd < 0)
1271 perror ("accept()");
1273 else
1275 time_t tt;
1276 char *ctt;
1278 /* new list entry for the connection */
1279 lappend (listener_list);
1280 j = listener_list.tail;
1281 j->http_request = (char *) strdup ("");
1282 j->http_state = HTTP_STATE_REQUEST;
1283 j->fd = accept_fd;
1285 j->tls_session = tls_session;
1286 gnutls_transport_set_ptr (tls_session,
1287 (gnutls_transport_ptr_t)
1288 gl_fd_to_handle (accept_fd));
1289 j->handshake_ok = 0;
1291 if (verbose != 0)
1293 tt = time (0);
1294 ctt = ctime (&tt);
1295 ctt[strlen (ctt) - 1] = 0;
1297 printf ("\n* Accepted connection from %s on %s\n",
1298 human_addr ((struct sockaddr *)
1299 &client_address, calen, topbuf,
1300 sizeof (topbuf)), ctt);
1305 if (FD_ISSET (j->fd, &rd) && !j->listen_socket)
1307 /* read partial GET request */
1308 char buf[1024];
1309 int r, ret;
1311 if (j->handshake_ok == 0)
1313 r = gnutls_handshake (j->tls_session);
1314 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1316 check_alert (j->tls_session, r);
1317 /* nothing */
1319 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1321 check_alert (j->tls_session, r);
1322 fprintf (stderr, "Error in handshake\n");
1323 GERR (r);
1327 ret =
1328 gnutls_alert_send_appropriate (j->tls_session, r);
1330 while (ret == GNUTLS_E_AGAIN
1331 || ret == GNUTLS_E_INTERRUPTED);
1332 j->http_state = HTTP_STATE_CLOSING;
1334 else if (r == 0)
1336 if (gnutls_session_is_resumed (j->tls_session) != 0
1337 && verbose != 0)
1338 printf ("*** This is a resumed session\n");
1340 if (verbose != 0)
1342 printf ("\n* Successful handshake from %s\n",
1343 human_addr ((struct sockaddr *)
1344 &client_address, calen, topbuf,
1345 sizeof (topbuf)));
1346 print_info (j->tls_session, verbose, verbose);
1347 if (gnutls_auth_get_type (j->tls_session) ==
1348 GNUTLS_CRD_CERTIFICATE)
1349 cert_verify (j->tls_session, NULL);
1351 j->handshake_ok = 1;
1355 if (j->handshake_ok == 1)
1357 r = gnutls_record_recv (j->tls_session, buf,
1358 MIN (1024, SMALL_READ_TEST));
1359 if (r == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
1361 gnutls_heartbeat_pong(j->tls_session, 0);
1363 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1365 /* do nothing */
1367 else if (r <= 0)
1369 if (r == GNUTLS_E_REHANDSHAKE)
1371 fprintf (stderr, "*** Received hello message\n");
1374 r = gnutls_handshake (j->tls_session);
1376 while (r == GNUTLS_E_INTERRUPTED
1377 || r == GNUTLS_E_AGAIN);
1379 if (r < 0)
1383 ret = gnutls_alert_send_appropriate
1384 (j->tls_session, r);
1386 while (ret == GNUTLS_E_AGAIN
1387 || ret == GNUTLS_E_INTERRUPTED);
1389 GERR (r);
1390 j->http_state = HTTP_STATE_CLOSING;
1393 else
1395 if (r < 0)
1397 if (r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1399 j->http_state = HTTP_STATE_CLOSING;
1400 check_alert (j->tls_session, r);
1401 fprintf (stderr,
1402 "Error while receiving data\n");
1403 GERR (r);
1408 else
1410 j->http_request =
1411 realloc (j->http_request, j->request_length + r + 1);
1412 if (j->http_request != NULL)
1414 memcpy (j->http_request + j->request_length, buf, r);
1415 j->request_length += r;
1416 j->http_request[j->request_length] = '\0';
1418 else
1419 j->http_state = HTTP_STATE_CLOSING;
1422 /* check if we have a full HTTP header */
1424 j->http_response = NULL;
1425 if (j->http_request != NULL)
1427 if ((http == 0 && strchr (j->http_request, '\n'))
1428 || strstr (j->http_request, "\r\n\r\n")
1429 || strstr (j->http_request, "\n\n"))
1431 get_response (j->tls_session, j->http_request,
1432 &j->http_response, &j->response_length);
1433 j->http_state = HTTP_STATE_RESPONSE;
1434 j->response_written = 0;
1439 if (FD_ISSET (j->fd, &wr))
1441 /* write partial response request */
1442 int r;
1444 if (j->handshake_ok == 0)
1446 r = gnutls_handshake (j->tls_session);
1447 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1449 check_alert (j->tls_session, r);
1450 /* nothing */
1452 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1454 int ret;
1456 j->http_state = HTTP_STATE_CLOSING;
1457 check_alert (j->tls_session, r);
1458 fprintf (stderr, "Error in handshake\n");
1459 GERR (r);
1463 ret =
1464 gnutls_alert_send_appropriate (j->tls_session, r);
1466 while (ret == GNUTLS_E_AGAIN);
1468 else if (r == 0)
1470 if (gnutls_session_is_resumed (j->tls_session) != 0
1471 && verbose != 0)
1472 printf ("*** This is a resumed session\n");
1473 if (verbose != 0)
1475 printf ("- connection from %s\n",
1476 human_addr ((struct sockaddr *)
1477 &client_address, calen, topbuf,
1478 sizeof (topbuf)));
1480 print_info (j->tls_session, verbose, verbose);
1481 if (gnutls_auth_get_type (j->tls_session) ==
1482 GNUTLS_CRD_CERTIFICATE)
1483 cert_verify (j->tls_session, NULL);
1485 j->handshake_ok = 1;
1489 if (j->handshake_ok == 1 && j->http_response != NULL)
1491 /* FIXME if j->http_response == NULL? */
1492 r = gnutls_record_send (j->tls_session,
1493 j->http_response +
1494 j->response_written,
1495 MIN (j->response_length -
1496 j->response_written,
1497 SMALL_READ_TEST));
1498 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1500 /* do nothing */
1502 else if (r <= 0)
1504 if (http != 0)
1505 j->http_state = HTTP_STATE_CLOSING;
1506 else
1508 j->http_state = HTTP_STATE_REQUEST;
1509 free (j->http_response);
1510 j->response_length = 0;
1511 j->request_length = 0;
1512 j->http_request[0] = 0;
1515 if (r < 0)
1517 fprintf (stderr, "Error while sending data\n");
1518 GERR (r);
1520 check_alert (j->tls_session, r);
1522 else
1524 j->response_written += r;
1525 /* check if we have written a complete response */
1526 if (j->response_written == j->response_length)
1528 if (http != 0)
1529 j->http_state = HTTP_STATE_CLOSING;
1530 else
1532 j->http_state = HTTP_STATE_REQUEST;
1533 free (j->http_response);
1534 j->response_length = 0;
1535 j->request_length = 0;
1536 j->http_request[0] = 0;
1541 else
1543 j->request_length = 0;
1544 j->http_request[0] = 0;
1545 j->http_state = HTTP_STATE_REQUEST;
1549 lloopend (listener_list, j);
1551 /* loop through all connections, closing those that are in error */
1552 lloopstart (listener_list, j)
1554 if (j->http_state == HTTP_STATE_CLOSING)
1556 ldeleteinc (listener_list, j);
1559 lloopend (listener_list, j);
1563 gnutls_certificate_free_credentials (cert_cred);
1565 #ifdef ENABLE_SRP
1566 if (srp_cred)
1567 gnutls_srp_free_server_credentials (srp_cred);
1568 #endif
1570 #ifdef ENABLE_PSK
1571 if (psk_cred)
1572 gnutls_psk_free_server_credentials (psk_cred);
1573 #endif
1575 #ifdef ENABLE_ANON
1576 gnutls_anon_free_server_credentials (dh_cred);
1577 #endif
1579 #ifdef ENABLE_SESSION_TICKET
1580 if (noticket == 0)
1581 gnutls_free (session_ticket_key.data);
1582 #endif
1584 if (nodb == 0)
1585 wrap_db_deinit ();
1586 gnutls_global_deinit ();
1590 static void
1591 cmd_parser (int argc, char **argv)
1593 optionProcess (&gnutls_servOptions, argc, argv);
1595 disable_client_cert = HAVE_OPT (DISABLE_CLIENT_CERT);
1596 require_cert = HAVE_OPT (REQUIRE_CLIENT_CERT);
1597 if (HAVE_OPT (DEBUG))
1598 debug = OPT_VALUE_DEBUG;
1600 if (HAVE_OPT (QUIET))
1601 verbose = 0;
1603 if (HAVE_OPT (PRIORITY))
1604 priorities = OPT_ARG (PRIORITY);
1606 if (HAVE_OPT (LIST))
1608 print_list (priorities, verbose);
1609 exit (0);
1612 nodb = HAVE_OPT (NODB);
1613 noticket = HAVE_OPT (NOTICKET);
1615 if (HAVE_OPT (ECHO))
1616 http = 0;
1617 else
1618 http = 1;
1620 if (HAVE_OPT (X509FMTDER))
1621 x509ctype = GNUTLS_X509_FMT_DER;
1622 else
1623 x509ctype = GNUTLS_X509_FMT_PEM;
1625 generate = HAVE_OPT (GENERATE);
1627 if (HAVE_OPT (DHPARAMS))
1628 dh_params_file = OPT_ARG (DHPARAMS);
1630 if (HAVE_OPT (X509KEYFILE))
1631 x509_keyfile = OPT_ARG (X509KEYFILE);
1632 if (HAVE_OPT (X509CERTFILE))
1633 x509_certfile = OPT_ARG (X509CERTFILE);
1635 if (HAVE_OPT (X509DSAKEYFILE))
1636 x509_dsakeyfile = OPT_ARG (X509DSAKEYFILE);
1637 if (HAVE_OPT (X509DSACERTFILE))
1638 x509_dsacertfile = OPT_ARG (X509DSACERTFILE);
1641 if (HAVE_OPT (X509ECCKEYFILE))
1642 x509_ecckeyfile = OPT_ARG (X509ECCKEYFILE);
1643 if (HAVE_OPT (X509CERTFILE))
1644 x509_ecccertfile = OPT_ARG (X509ECCCERTFILE);
1646 if (HAVE_OPT (X509CAFILE))
1647 x509_cafile = OPT_ARG (X509CAFILE);
1648 if (HAVE_OPT (X509CRLFILE))
1649 x509_crlfile = OPT_ARG (X509CRLFILE);
1651 if (HAVE_OPT (PGPKEYFILE))
1652 pgp_keyfile = OPT_ARG (PGPKEYFILE);
1653 if (HAVE_OPT (PGPCERTFILE))
1654 pgp_certfile = OPT_ARG (PGPCERTFILE);
1656 if (HAVE_OPT (PGPKEYRING))
1657 pgp_keyring = OPT_ARG (PGPKEYRING);
1659 if (HAVE_OPT (SRPPASSWD))
1660 srp_passwd = OPT_ARG (SRPPASSWD);
1661 if (HAVE_OPT (SRPPASSWDCONF))
1662 srp_passwd_conf = OPT_ARG (SRPPASSWDCONF);
1664 if (HAVE_OPT (PSKPASSWD))
1665 psk_passwd = OPT_ARG (PSKPASSWD);
1667 if (HAVE_OPT(STATUS_RESPONSE_OCSP))
1668 status_response_ocsp = OPT_ARG(STATUS_RESPONSE_OCSP);
1672 /* session resuming support */
1674 #define SESSION_ID_SIZE 32
1675 #define SESSION_DATA_SIZE 1024
1677 typedef struct
1679 char session_id[SESSION_ID_SIZE];
1680 unsigned int session_id_size;
1682 char session_data[SESSION_DATA_SIZE];
1683 unsigned int session_data_size;
1684 } CACHE;
1686 static CACHE *cache_db;
1687 int cache_db_ptr = 0;
1689 static void
1690 wrap_db_init (void)
1692 /* allocate cache_db */
1693 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1696 static void
1697 wrap_db_deinit (void)
1701 static int
1702 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1705 if (cache_db == NULL)
1706 return -1;
1708 if (key.size > SESSION_ID_SIZE)
1709 return -1;
1710 if (data.size > SESSION_DATA_SIZE)
1711 return -1;
1713 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1714 cache_db[cache_db_ptr].session_id_size = key.size;
1716 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1717 cache_db[cache_db_ptr].session_data_size = data.size;
1719 cache_db_ptr++;
1720 cache_db_ptr %= ssl_session_cache;
1722 return 0;
1725 static gnutls_datum_t
1726 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1728 gnutls_datum_t res = { NULL, 0 };
1729 int i;
1731 if (cache_db == NULL)
1732 return res;
1734 for (i = 0; i < ssl_session_cache; i++)
1736 if (key.size == cache_db[i].session_id_size &&
1737 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1739 res.size = cache_db[i].session_data_size;
1741 res.data = gnutls_malloc (res.size);
1742 if (res.data == NULL)
1743 return res;
1745 memcpy (res.data, cache_db[i].session_data, res.size);
1747 return res;
1750 return res;
1753 static int
1754 wrap_db_delete (void *dbf, gnutls_datum_t key)
1756 int i;
1758 if (cache_db == NULL)
1759 return -1;
1761 for (i = 0; i < ssl_session_cache; i++)
1763 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1764 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1767 cache_db[i].session_id_size = 0;
1768 cache_db[i].session_data_size = 0;
1770 return 0;
1774 return -1;