_gnutls_strdatum_to_buf() will account for NULL input.
[gnutls.git] / src / serv.c
blob3fc9845c0d8875bb7d5eb0df8ea11157ffe32fc0
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 int ret;
337 const char *err;
339 if (priorities == NULL)
340 priorities = "NORMAL";
342 if (dtls)
343 gnutls_init (&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
344 else
345 gnutls_init (&session, GNUTLS_SERVER);
347 /* allow the use of private ciphersuites.
349 gnutls_handshake_set_private_extensions (session, 1);
351 if (nodb == 0)
353 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
354 gnutls_db_set_remove_function (session, wrap_db_delete);
355 gnutls_db_set_store_function (session, wrap_db_store);
356 gnutls_db_set_ptr (session, NULL);
358 #ifdef ENABLE_SESSION_TICKET
359 if (noticket == 0)
360 gnutls_session_ticket_enable_server (session, &session_ticket_key);
361 #endif
364 if (noticket == 0)
365 gnutls_session_ticket_enable_server (session, &session_ticket_key);
367 if (gnutls_priority_set_direct (session, priorities, &err) < 0)
369 fprintf (stderr, "Syntax error at: %s\n", err);
370 exit (1);
373 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
375 if (srp_cred != NULL)
376 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
378 if (psk_cred != NULL)
379 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
381 if (cert_cred != NULL)
382 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
384 if (disable_client_cert)
385 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
386 else
388 if (require_cert)
389 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
390 else
391 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
394 if (HAVE_OPT (HEARTBEAT))
395 gnutls_heartbeat_enable(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND);
397 #ifdef ENABLE_DTLS_SRTP
398 if (HAVE_OPT (SRTP_PROFILES))
400 ret = gnutls_srtp_set_profile_direct (session, OPT_ARG(SRTP_PROFILES), &err);
401 if (ret == GNUTLS_E_INVALID_REQUEST) fprintf (stderr, "Syntax error at: %s\n", err);
402 else
403 fprintf(stderr, "Error in profiles: %s\n", gnutls_strerror(ret));
404 exit (1);
406 #endif
408 return session;
411 #include <gnutls/x509.h>
413 static const char DEFAULT_DATA[] =
414 "This is the default message reported by the GnuTLS implementation. "
415 "For more information please visit "
416 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
418 /* Creates html with the current session information.
420 #define tmp_buffer &http_buffer[strlen(http_buffer)]
421 #define tmp_buffer_size len-strlen(http_buffer)
422 static char *
423 peer_print_info (gnutls_session_t session, int *ret_length,
424 const char *header)
426 const char *tmp;
427 unsigned char sesid[32];
428 size_t i, sesid_size;
429 char *http_buffer;
430 gnutls_kx_algorithm_t kx_alg;
431 size_t len = 20 * 1024 + strlen (header);
432 char *crtinfo = NULL;
433 size_t ncrtinfo = 0;
435 if (verbose == 0)
437 http_buffer = malloc (len);
438 if (http_buffer == NULL)
439 return NULL;
441 strcpy (http_buffer, HTTP_BEGIN);
442 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
443 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
444 HTTP_END);
445 *ret_length =
446 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
447 return http_buffer;
450 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
452 const gnutls_datum_t *cert_list;
453 unsigned int cert_list_size = 0;
455 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
457 for (i = 0; i < cert_list_size; i++)
459 gnutls_x509_crt_t cert;
460 gnutls_datum_t info;
462 if (gnutls_x509_crt_init (&cert) == 0 &&
463 gnutls_x509_crt_import (cert, &cert_list[i],
464 GNUTLS_X509_FMT_DER) == 0 &&
465 gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &info) == 0)
467 const char *post = "</PRE><P><PRE>";
469 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
470 strlen (post) + 1);
471 if (crtinfo == NULL)
472 return NULL;
473 memcpy (crtinfo + ncrtinfo, info.data, info.size);
474 ncrtinfo += info.size;
475 memcpy (crtinfo + ncrtinfo, post, strlen (post));
476 ncrtinfo += strlen (post);
477 crtinfo[ncrtinfo] = '\0';
478 gnutls_free (info.data);
483 http_buffer = malloc (len);
484 if (http_buffer == NULL)
486 free (crtinfo);
487 return NULL;
490 strcpy (http_buffer, HTTP_BEGIN);
492 /* print session_id */
493 sesid_size = sizeof(sesid);
494 gnutls_session_get_id (session, sesid, &sesid_size);
495 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Session ID: <i>");
496 for (i = 0; i < sesid_size; i++)
497 snprintf (tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
498 snprintf (tmp_buffer, tmp_buffer_size, "</i></p>\n");
499 snprintf (tmp_buffer, tmp_buffer_size,
500 "<h5>If your browser supports session resuming, then you should see the "
501 "same session ID, when you press the <b>reload</b> button.</h5>\n");
503 /* Here unlike print_info() we use the kx algorithm to distinguish
504 * the functions to call.
507 char dns[256];
508 size_t dns_size = sizeof (dns);
509 unsigned int type;
511 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
513 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Server Name: %s</p>\n",
514 dns);
519 kx_alg = gnutls_kx_get (session);
521 /* print srp specific data */
522 #ifdef ENABLE_SRP
523 if (kx_alg == GNUTLS_KX_SRP)
525 snprintf (tmp_buffer, tmp_buffer_size,
526 "<p>Connected as user '%s'.</p>\n",
527 gnutls_srp_server_get_username (session));
529 #endif
531 #ifdef ENABLE_PSK
532 if (kx_alg == GNUTLS_KX_PSK)
534 snprintf (tmp_buffer, tmp_buffer_size,
535 "<p>Connected as user '%s'.</p>\n",
536 gnutls_psk_server_get_username (session));
538 #endif
540 #ifdef ENABLE_ANON
541 if (kx_alg == GNUTLS_KX_ANON_DH)
543 snprintf (tmp_buffer, tmp_buffer_size,
544 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
545 gnutls_dh_get_prime_bits (session));
547 #endif
549 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
551 snprintf (tmp_buffer, tmp_buffer_size,
552 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
553 gnutls_dh_get_prime_bits (session));
556 /* print session information */
557 strcat (http_buffer, "<P>\n");
559 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
560 if (tmp == NULL)
561 tmp = str_unknown;
562 snprintf (tmp_buffer, tmp_buffer_size,
563 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
564 tmp);
566 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
568 tmp =
569 gnutls_certificate_type_get_name (gnutls_certificate_type_get
570 (session));
571 if (tmp == NULL)
572 tmp = str_unknown;
573 snprintf (tmp_buffer, tmp_buffer_size,
574 "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
577 tmp = gnutls_kx_get_name (kx_alg);
578 if (tmp == NULL)
579 tmp = str_unknown;
580 snprintf (tmp_buffer, tmp_buffer_size,
581 "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
583 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
584 if (tmp == NULL)
585 tmp = str_unknown;
586 snprintf (tmp_buffer, tmp_buffer_size,
587 "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
589 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
590 if (tmp == NULL)
591 tmp = str_unknown;
592 snprintf (tmp_buffer, tmp_buffer_size,
593 "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
595 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
596 if (tmp == NULL)
597 tmp = str_unknown;
598 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n",
599 tmp);
601 tmp = gnutls_cipher_suite_get_name (kx_alg,
602 gnutls_cipher_get (session),
603 gnutls_mac_get (session));
604 if (tmp == NULL)
605 tmp = str_unknown;
606 snprintf (tmp_buffer, tmp_buffer_size,
607 "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n", tmp);
609 if (crtinfo)
611 snprintf (tmp_buffer, tmp_buffer_size, "<hr><PRE>%s\n</PRE>\n",
612 crtinfo);
613 free (crtinfo);
616 snprintf (tmp_buffer, tmp_buffer_size,
617 "<hr><P>Your HTTP header was:<PRE>%s</PRE></P>\n" HTTP_END,
618 header);
620 *ret_length = strlen (http_buffer);
622 return http_buffer;
625 const char *
626 human_addr (const struct sockaddr *sa, socklen_t salen,
627 char *buf, size_t buflen)
629 const char *save_buf = buf;
630 size_t l;
632 if (!buf || !buflen)
633 return NULL;
635 *buf = '\0';
637 switch (sa->sa_family)
639 #if HAVE_IPV6
640 case AF_INET6:
641 snprintf (buf, buflen, "IPv6 ");
642 break;
643 #endif
645 case AF_INET:
646 snprintf (buf, buflen, "IPv4 ");
647 break;
650 l = strlen (buf);
651 buf += l;
652 buflen -= l;
654 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
655 return NULL;
657 l = strlen (buf);
658 buf += l;
659 buflen -= l;
661 strncat (buf, " port ", buflen);
663 l = strlen (buf);
664 buf += l;
665 buflen -= l;
667 if (getnameinfo (sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
668 return NULL;
670 return save_buf;
674 wait_for_connection (void)
676 listener_item *j;
677 fd_set rd, wr;
678 int n, sock = -1;
680 FD_ZERO (&rd);
681 FD_ZERO (&wr);
682 n = 0;
684 lloopstart (listener_list, j)
686 if (j->listen_socket)
688 FD_SET (j->fd, &rd);
689 n = MAX (n, j->fd);
692 lloopend (listener_list, j);
694 /* waiting part */
695 n = select (n + 1, &rd, &wr, NULL, NULL);
696 if (n == -1 && errno == EINTR)
697 return -1;
698 if (n < 0)
700 perror ("select()");
701 exit (1);
704 /* find which one is ready */
705 lloopstart (listener_list, j)
707 /* a new connection has arrived */
708 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
710 sock = j->fd;
711 break;
714 lloopend (listener_list, j);
715 return sock;
719 listen_socket (const char *name, int listen_port, int socktype)
721 struct addrinfo hints, *res, *ptr;
722 char portname[6];
723 int s;
724 int yes;
725 listener_item *j = NULL;
727 snprintf (portname, sizeof (portname), "%d", listen_port);
728 memset (&hints, 0, sizeof (hints));
729 hints.ai_socktype = socktype;
730 hints.ai_flags = AI_PASSIVE
731 #ifdef AI_ADDRCONFIG
732 | AI_ADDRCONFIG
733 #endif
736 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
738 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
739 return -1;
742 for (ptr = res; ptr != NULL; ptr = ptr->ai_next)
744 #ifndef HAVE_IPV6
745 if (ptr->ai_family != AF_INET)
746 continue;
747 #endif
749 /* Print what we are doing. */
751 char topbuf[512];
753 fprintf (stderr, "%s listening on %s...",
754 name, human_addr (ptr->ai_addr, ptr->ai_addrlen,
755 topbuf, sizeof (topbuf)));
758 if ((s = socket (ptr->ai_family, ptr->ai_socktype,
759 ptr->ai_protocol)) < 0)
761 perror ("socket() failed");
762 continue;
765 #if defined(HAVE_IPV6) && !defined(_WIN32)
766 if (ptr->ai_family == AF_INET6)
768 yes = 1;
769 /* avoid listen on ipv6 addresses failing
770 * because already listening on ipv4 addresses: */
771 setsockopt (s, IPPROTO_IPV6, IPV6_V6ONLY,
772 (const void *) &yes, sizeof (yes));
774 #endif
776 if (socktype == SOCK_STREAM)
778 yes = 1;
779 if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
780 (const void *) &yes, sizeof (yes)) < 0)
782 perror ("setsockopt() failed");
783 close (s);
784 continue;
787 else
789 #if defined(IP_DONTFRAG)
790 yes = 1;
791 if (setsockopt (s, IPPROTO_IP, IP_DONTFRAG,
792 (const void *) &yes, sizeof (yes)) < 0)
793 perror ("setsockopt(IP_DF) failed");
794 #elif defined(IP_MTU_DISCOVER)
795 yes = IP_PMTUDISC_DO;
796 if (setsockopt (s, IPPROTO_IP, IP_MTU_DISCOVER,
797 (const void *) &yes, sizeof (yes)) < 0)
798 perror ("setsockopt(IP_DF) failed");
799 #endif
802 if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
804 perror ("bind() failed");
805 close (s);
806 continue;
809 if (socktype == SOCK_STREAM)
811 if (listen (s, 10) < 0)
813 perror ("listen() failed");
814 exit (1);
818 /* new list entry for the connection */
819 lappend (listener_list);
820 j = listener_list.tail;
821 j->listen_socket = 1;
822 j->fd = s;
824 /* Complete earlier message. */
825 fprintf (stderr, "done\n");
828 fflush (stderr);
830 freeaddrinfo (res);
832 return s;
835 /* strips \r\n from the end of the string
837 static void
838 strip (char *data)
840 int i;
841 int len = strlen (data);
843 for (i = 0; i < len; i++)
845 if (data[i] == '\r' && data[i + 1] == '\n' && data[i + 1] == 0)
847 data[i] = '\n';
848 data[i + 1] = 0;
849 break;
854 static void
855 get_response (gnutls_session_t session, char *request,
856 char **response, int *response_length)
858 char *p, *h;
860 if (http != 0)
862 if (strncmp (request, "GET ", 4))
863 goto unimplemented;
865 if (!(h = strchr (request, '\n')))
866 goto unimplemented;
868 *h++ = '\0';
869 while (*h == '\r' || *h == '\n')
870 h++;
872 if (!(p = strchr (request + 4, ' ')))
873 goto unimplemented;
874 *p = '\0';
876 /* *response = peer_print_info(session, request+4, h, response_length); */
877 if (http != 0)
879 *response = peer_print_info (session, response_length, h);
881 else
883 strip (request);
884 fprintf (stderr, "received: %s\n", request);
885 if (check_command (session, request))
887 *response = NULL;
888 *response_length = 0;
889 return;
891 *response = strdup (request);
892 *response_length = ((*response) ? strlen (*response) : 0);
895 return;
897 unimplemented:
898 *response = strdup (HTTP_UNIMPLEMENTED);
899 *response_length = ((*response) ? strlen (*response) : 0);
902 static void terminate (int sig) __attribute__ ((noreturn));
904 static void
905 terminate (int sig)
907 fprintf (stderr, "Exiting via signal %d\n", sig);
908 exit (1);
912 static void
913 check_alert (gnutls_session_t session, int ret)
915 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
916 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
918 int last_alert = gnutls_alert_get (session);
919 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
920 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
921 printf
922 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
923 else
924 printf ("* Received alert '%d': %s.\n", last_alert,
925 gnutls_alert_get_name (last_alert));
929 static void
930 tls_log_func (int level, const char *str)
932 fprintf (stderr, "|<%d>| %s", level, str);
935 static void
936 tls_audit_log_func (gnutls_session_t session, const char *str)
938 fprintf (stderr, "|<%p>| %s", session, str);
942 main (int argc, char **argv)
944 int ret, mtu, port;
945 char name[256];
947 set_program_name (argv[0]);
948 cmd_parser (argc, argv);
950 #ifndef _WIN32
951 signal (SIGHUP, SIG_IGN);
952 signal (SIGTERM, terminate);
953 if (signal (SIGINT, terminate) == SIG_IGN)
954 signal (SIGINT, SIG_IGN); /* e.g. background process */
955 #endif
957 sockets_init ();
959 if (nodb == 0)
960 wrap_db_init ();
962 if (HAVE_OPT (UDP))
963 strcpy (name, "UDP ");
964 else
965 name[0] = 0;
967 if (http == 1)
969 strcat (name, "HTTP Server");
971 else
973 strcat (name, "Echo Server");
976 gnutls_global_set_log_function (tls_log_func);
977 gnutls_global_set_audit_log_function (tls_audit_log_func);
978 gnutls_global_set_log_level (debug);
980 if ((ret = gnutls_global_init ()) < 0)
982 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
983 exit (1);
986 #ifdef ENABLE_PKCS11
987 pkcs11_common ();
988 #endif
990 /* Note that servers must generate parameters for
991 * Diffie-Hellman. See gnutls_dh_params_generate(), and
992 * gnutls_dh_params_set().
994 if (generate != 0)
996 generate_rsa_params ();
997 generate_dh_primes ();
999 else if (dh_params_file)
1001 read_dh_params ();
1003 else
1005 static_dh_params ();
1008 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
1010 fprintf (stderr, "memory error\n");
1011 exit (1);
1014 if (x509_cafile != NULL)
1016 if ((ret = gnutls_certificate_set_x509_trust_file
1017 (cert_cred, x509_cafile, x509ctype)) < 0)
1019 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
1020 GERR (ret);
1021 exit (1);
1023 else
1025 printf ("Processed %d CA certificate(s).\n", ret);
1028 if (x509_crlfile != NULL)
1030 if ((ret = gnutls_certificate_set_x509_crl_file
1031 (cert_cred, x509_crlfile, x509ctype)) < 0)
1033 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
1034 GERR (ret);
1035 exit (1);
1037 else
1039 printf ("Processed %d CRL(s).\n", ret);
1043 #ifdef ENABLE_OPENPGP
1044 if (pgp_keyring != NULL)
1046 ret =
1047 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring,
1048 GNUTLS_OPENPGP_FMT_BASE64);
1049 if (ret < 0)
1051 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
1052 GERR (ret);
1056 if (HAVE_OPT (PGPCERTFILE))
1058 if (HAVE_OPT (PGPSUBKEY))
1059 ret = gnutls_certificate_set_openpgp_key_file2
1060 (cert_cred, pgp_certfile, pgp_keyfile, OPT_ARG (PGPSUBKEY),
1061 GNUTLS_OPENPGP_FMT_BASE64);
1062 else
1063 ret = gnutls_certificate_set_openpgp_key_file
1064 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64);
1066 if (ret < 0)
1068 fprintf (stderr,
1069 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1070 ret, pgp_certfile, pgp_keyfile);
1071 GERR (ret);
1074 #endif
1076 if (x509_certfile != NULL)
1077 if ((ret = gnutls_certificate_set_x509_key_file
1078 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
1080 fprintf (stderr,
1081 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1082 GERR (ret);
1083 exit (1);
1086 if (x509_dsacertfile != NULL)
1087 if ((ret = gnutls_certificate_set_x509_key_file
1088 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1090 fprintf (stderr, "Error reading '%s' or '%s'\n",
1091 x509_dsacertfile, x509_dsakeyfile);
1092 GERR (ret);
1093 exit (1);
1096 if (x509_ecccertfile != NULL)
1097 if ((ret = gnutls_certificate_set_x509_key_file
1098 (cert_cred, x509_ecccertfile, x509_ecckeyfile, x509ctype)) < 0)
1100 fprintf (stderr, "Error reading '%s' or '%s'\n",
1101 x509_ecccertfile, x509_ecckeyfile);
1102 GERR (ret);
1103 exit (1);
1106 /* OCSP status-request TLS extension */
1107 if (status_response_ocsp)
1109 if (gnutls_certificate_set_ocsp_status_request_file (cert_cred, status_response_ocsp, 0) < 0)
1111 fprintf (stderr, "Cannot set OCSP status request file: %s\n", gnutls_strerror(ret));
1112 exit (1);
1116 gnutls_certificate_set_params_function (cert_cred, get_params);
1117 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1118 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1121 /* this is a password file (created with the included srpcrypt utility)
1122 * Read README.crypt prior to using SRP.
1124 #ifdef ENABLE_SRP
1125 if (srp_passwd != NULL)
1127 gnutls_srp_allocate_server_credentials (&srp_cred);
1129 if ((ret =
1130 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1131 srp_passwd_conf)) < 0)
1133 /* only exit is this function is not disabled
1135 fprintf (stderr, "Error while setting SRP parameters\n");
1136 GERR (ret);
1139 #endif
1141 /* this is a password file
1143 #ifdef ENABLE_PSK
1144 if (psk_passwd != NULL)
1146 gnutls_psk_allocate_server_credentials (&psk_cred);
1148 if ((ret =
1149 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1151 /* only exit is this function is not disabled
1153 fprintf (stderr, "Error while setting PSK parameters\n");
1154 GERR (ret);
1157 if (HAVE_OPT (PSKHINT))
1159 ret = gnutls_psk_set_server_credentials_hint (psk_cred,
1160 OPT_ARG (PSKHINT));
1161 if (ret)
1163 fprintf (stderr, "Error setting PSK identity hint.\n");
1164 GERR (ret);
1168 gnutls_psk_set_server_params_function (psk_cred, get_params);
1170 #endif
1172 #ifdef ENABLE_ANON
1173 gnutls_anon_allocate_server_credentials (&dh_cred);
1174 gnutls_anon_set_server_params_function (dh_cred, get_params);
1176 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1177 #endif
1179 #ifdef ENABLE_SESSION_TICKET
1180 if (noticket == 0)
1181 gnutls_session_ticket_key_generate (&session_ticket_key);
1182 #endif
1184 if (HAVE_OPT (MTU))
1185 mtu = OPT_VALUE_MTU;
1186 else
1187 mtu = 1300;
1189 if (HAVE_OPT (PORT))
1190 port = OPT_VALUE_PORT;
1191 else
1192 port = 5556;
1194 if (HAVE_OPT (UDP))
1195 udp_server (name, port, mtu);
1196 else
1197 tcp_server (name, port);
1200 static void
1201 tcp_server (const char *name, int port)
1203 int n, s;
1204 char topbuf[512];
1205 int accept_fd;
1206 struct sockaddr_storage client_address;
1207 socklen_t calen;
1209 s = listen_socket (name, port, SOCK_STREAM);
1210 if (s < 0)
1211 exit (1);
1213 for (;;)
1215 listener_item *j;
1216 fd_set rd, wr;
1217 #ifndef _WIN32
1218 int val;
1219 #endif
1221 FD_ZERO (&rd);
1222 FD_ZERO (&wr);
1223 n = 0;
1225 /* flag which connections we are reading or writing to within the fd sets */
1226 lloopstart (listener_list, j)
1229 #ifndef _WIN32
1230 val = fcntl (j->fd, F_GETFL, 0);
1231 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1233 perror ("fcntl()");
1234 exit (1);
1236 #endif
1238 if (j->listen_socket)
1240 FD_SET (j->fd, &rd);
1241 n = MAX (n, j->fd);
1243 if (j->http_state == HTTP_STATE_REQUEST)
1245 FD_SET (j->fd, &rd);
1246 n = MAX (n, j->fd);
1248 if (j->http_state == HTTP_STATE_RESPONSE)
1250 FD_SET (j->fd, &wr);
1251 n = MAX (n, j->fd);
1254 lloopend (listener_list, j);
1256 /* core operation */
1257 n = select (n + 1, &rd, &wr, NULL, NULL);
1258 if (n == -1 && errno == EINTR)
1259 continue;
1260 if (n < 0)
1262 perror ("select()");
1263 exit (1);
1266 /* read or write to each connection as indicated by select()'s return argument */
1267 lloopstart (listener_list, j)
1270 /* a new connection has arrived */
1271 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
1273 gnutls_session_t tls_session;
1275 tls_session = initialize_session (0);
1277 calen = sizeof (client_address);
1278 memset (&client_address, 0, calen);
1279 accept_fd = accept (j->fd, (struct sockaddr *) &client_address,
1280 &calen);
1282 if (accept_fd < 0)
1284 perror ("accept()");
1286 else
1288 time_t tt;
1289 char *ctt;
1291 /* new list entry for the connection */
1292 lappend (listener_list);
1293 j = listener_list.tail;
1294 j->http_request = (char *) strdup ("");
1295 j->http_state = HTTP_STATE_REQUEST;
1296 j->fd = accept_fd;
1298 j->tls_session = tls_session;
1299 gnutls_transport_set_ptr (tls_session,
1300 (gnutls_transport_ptr_t)
1301 gl_fd_to_handle (accept_fd));
1302 j->handshake_ok = 0;
1304 if (verbose != 0)
1306 tt = time (0);
1307 ctt = ctime (&tt);
1308 ctt[strlen (ctt) - 1] = 0;
1310 printf ("\n* Accepted connection from %s on %s\n",
1311 human_addr ((struct sockaddr *)
1312 &client_address, calen, topbuf,
1313 sizeof (topbuf)), ctt);
1318 if (FD_ISSET (j->fd, &rd) && !j->listen_socket)
1320 /* read partial GET request */
1321 char buf[1024];
1322 int r, ret;
1324 if (j->handshake_ok == 0)
1326 r = gnutls_handshake (j->tls_session);
1327 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1329 check_alert (j->tls_session, r);
1330 /* nothing */
1332 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1334 check_alert (j->tls_session, r);
1335 fprintf (stderr, "Error in handshake\n");
1336 GERR (r);
1340 ret =
1341 gnutls_alert_send_appropriate (j->tls_session, r);
1343 while (ret == GNUTLS_E_AGAIN
1344 || ret == GNUTLS_E_INTERRUPTED);
1345 j->http_state = HTTP_STATE_CLOSING;
1347 else if (r == 0)
1349 if (gnutls_session_is_resumed (j->tls_session) != 0
1350 && verbose != 0)
1351 printf ("*** This is a resumed session\n");
1353 if (verbose != 0)
1355 printf ("\n* Successful handshake from %s\n",
1356 human_addr ((struct sockaddr *)
1357 &client_address, calen, topbuf,
1358 sizeof (topbuf)));
1359 print_info (j->tls_session, verbose, verbose);
1360 if (gnutls_auth_get_type (j->tls_session) ==
1361 GNUTLS_CRD_CERTIFICATE)
1362 cert_verify (j->tls_session, NULL);
1364 j->handshake_ok = 1;
1368 if (j->handshake_ok == 1)
1370 r = gnutls_record_recv (j->tls_session, buf,
1371 MIN (1024, SMALL_READ_TEST));
1372 if (r == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
1374 gnutls_heartbeat_pong(j->tls_session, 0);
1376 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1378 /* do nothing */
1380 else if (r <= 0)
1382 if (r == GNUTLS_E_REHANDSHAKE)
1384 fprintf (stderr, "*** Received hello message\n");
1387 r = gnutls_handshake (j->tls_session);
1389 while (r == GNUTLS_E_INTERRUPTED
1390 || r == GNUTLS_E_AGAIN);
1392 if (r < 0)
1396 ret = gnutls_alert_send_appropriate
1397 (j->tls_session, r);
1399 while (ret == GNUTLS_E_AGAIN
1400 || ret == GNUTLS_E_INTERRUPTED);
1402 GERR (r);
1403 j->http_state = HTTP_STATE_CLOSING;
1406 else
1408 if (r < 0)
1410 if (r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1412 j->http_state = HTTP_STATE_CLOSING;
1413 check_alert (j->tls_session, r);
1414 fprintf (stderr,
1415 "Error while receiving data\n");
1416 GERR (r);
1421 else
1423 j->http_request =
1424 realloc (j->http_request, j->request_length + r + 1);
1425 if (j->http_request != NULL)
1427 memcpy (j->http_request + j->request_length, buf, r);
1428 j->request_length += r;
1429 j->http_request[j->request_length] = '\0';
1431 else
1432 j->http_state = HTTP_STATE_CLOSING;
1435 /* check if we have a full HTTP header */
1437 j->http_response = NULL;
1438 if (j->http_request != NULL)
1440 if ((http == 0 && strchr (j->http_request, '\n'))
1441 || strstr (j->http_request, "\r\n\r\n")
1442 || strstr (j->http_request, "\n\n"))
1444 get_response (j->tls_session, j->http_request,
1445 &j->http_response, &j->response_length);
1446 j->http_state = HTTP_STATE_RESPONSE;
1447 j->response_written = 0;
1452 if (FD_ISSET (j->fd, &wr))
1454 /* write partial response request */
1455 int r;
1457 if (j->handshake_ok == 0)
1459 r = gnutls_handshake (j->tls_session);
1460 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1462 check_alert (j->tls_session, r);
1463 /* nothing */
1465 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1467 int ret;
1469 j->http_state = HTTP_STATE_CLOSING;
1470 check_alert (j->tls_session, r);
1471 fprintf (stderr, "Error in handshake\n");
1472 GERR (r);
1476 ret =
1477 gnutls_alert_send_appropriate (j->tls_session, r);
1479 while (ret == GNUTLS_E_AGAIN);
1481 else if (r == 0)
1483 if (gnutls_session_is_resumed (j->tls_session) != 0
1484 && verbose != 0)
1485 printf ("*** This is a resumed session\n");
1486 if (verbose != 0)
1488 printf ("- connection from %s\n",
1489 human_addr ((struct sockaddr *)
1490 &client_address, calen, topbuf,
1491 sizeof (topbuf)));
1493 print_info (j->tls_session, verbose, verbose);
1494 if (gnutls_auth_get_type (j->tls_session) ==
1495 GNUTLS_CRD_CERTIFICATE)
1496 cert_verify (j->tls_session, NULL);
1498 j->handshake_ok = 1;
1502 if (j->handshake_ok == 1 && j->http_response != NULL)
1504 /* FIXME if j->http_response == NULL? */
1505 r = gnutls_record_send (j->tls_session,
1506 j->http_response +
1507 j->response_written,
1508 MIN (j->response_length -
1509 j->response_written,
1510 SMALL_READ_TEST));
1511 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1513 /* do nothing */
1515 else if (r <= 0)
1517 if (http != 0)
1518 j->http_state = HTTP_STATE_CLOSING;
1519 else
1521 j->http_state = HTTP_STATE_REQUEST;
1522 free (j->http_response);
1523 j->response_length = 0;
1524 j->request_length = 0;
1525 j->http_request[0] = 0;
1528 if (r < 0)
1530 fprintf (stderr, "Error while sending data\n");
1531 GERR (r);
1533 check_alert (j->tls_session, r);
1535 else
1537 j->response_written += r;
1538 /* check if we have written a complete response */
1539 if (j->response_written == j->response_length)
1541 if (http != 0)
1542 j->http_state = HTTP_STATE_CLOSING;
1543 else
1545 j->http_state = HTTP_STATE_REQUEST;
1546 free (j->http_response);
1547 j->response_length = 0;
1548 j->request_length = 0;
1549 j->http_request[0] = 0;
1554 else
1556 j->request_length = 0;
1557 j->http_request[0] = 0;
1558 j->http_state = HTTP_STATE_REQUEST;
1562 lloopend (listener_list, j);
1564 /* loop through all connections, closing those that are in error */
1565 lloopstart (listener_list, j)
1567 if (j->http_state == HTTP_STATE_CLOSING)
1569 ldeleteinc (listener_list, j);
1572 lloopend (listener_list, j);
1576 gnutls_certificate_free_credentials (cert_cred);
1578 #ifdef ENABLE_SRP
1579 if (srp_cred)
1580 gnutls_srp_free_server_credentials (srp_cred);
1581 #endif
1583 #ifdef ENABLE_PSK
1584 if (psk_cred)
1585 gnutls_psk_free_server_credentials (psk_cred);
1586 #endif
1588 #ifdef ENABLE_ANON
1589 gnutls_anon_free_server_credentials (dh_cred);
1590 #endif
1592 #ifdef ENABLE_SESSION_TICKET
1593 if (noticket == 0)
1594 gnutls_free (session_ticket_key.data);
1595 #endif
1597 if (nodb == 0)
1598 wrap_db_deinit ();
1599 gnutls_global_deinit ();
1603 static void
1604 cmd_parser (int argc, char **argv)
1606 optionProcess (&gnutls_servOptions, argc, argv);
1608 disable_client_cert = HAVE_OPT (DISABLE_CLIENT_CERT);
1609 require_cert = HAVE_OPT (REQUIRE_CLIENT_CERT);
1610 if (HAVE_OPT (DEBUG))
1611 debug = OPT_VALUE_DEBUG;
1613 if (HAVE_OPT (QUIET))
1614 verbose = 0;
1616 if (HAVE_OPT (PRIORITY))
1617 priorities = OPT_ARG (PRIORITY);
1619 if (HAVE_OPT (LIST))
1621 print_list (priorities, verbose);
1622 exit (0);
1625 nodb = HAVE_OPT (NODB);
1626 noticket = HAVE_OPT (NOTICKET);
1628 if (HAVE_OPT (ECHO))
1629 http = 0;
1630 else
1631 http = 1;
1633 if (HAVE_OPT (X509FMTDER))
1634 x509ctype = GNUTLS_X509_FMT_DER;
1635 else
1636 x509ctype = GNUTLS_X509_FMT_PEM;
1638 generate = HAVE_OPT (GENERATE);
1640 if (HAVE_OPT (DHPARAMS))
1641 dh_params_file = OPT_ARG (DHPARAMS);
1643 if (HAVE_OPT (X509KEYFILE))
1644 x509_keyfile = OPT_ARG (X509KEYFILE);
1645 if (HAVE_OPT (X509CERTFILE))
1646 x509_certfile = OPT_ARG (X509CERTFILE);
1648 if (HAVE_OPT (X509DSAKEYFILE))
1649 x509_dsakeyfile = OPT_ARG (X509DSAKEYFILE);
1650 if (HAVE_OPT (X509DSACERTFILE))
1651 x509_dsacertfile = OPT_ARG (X509DSACERTFILE);
1654 if (HAVE_OPT (X509ECCKEYFILE))
1655 x509_ecckeyfile = OPT_ARG (X509ECCKEYFILE);
1656 if (HAVE_OPT (X509CERTFILE))
1657 x509_ecccertfile = OPT_ARG (X509ECCCERTFILE);
1659 if (HAVE_OPT (X509CAFILE))
1660 x509_cafile = OPT_ARG (X509CAFILE);
1661 if (HAVE_OPT (X509CRLFILE))
1662 x509_crlfile = OPT_ARG (X509CRLFILE);
1664 if (HAVE_OPT (PGPKEYFILE))
1665 pgp_keyfile = OPT_ARG (PGPKEYFILE);
1666 if (HAVE_OPT (PGPCERTFILE))
1667 pgp_certfile = OPT_ARG (PGPCERTFILE);
1669 if (HAVE_OPT (PGPKEYRING))
1670 pgp_keyring = OPT_ARG (PGPKEYRING);
1672 if (HAVE_OPT (SRPPASSWD))
1673 srp_passwd = OPT_ARG (SRPPASSWD);
1674 if (HAVE_OPT (SRPPASSWDCONF))
1675 srp_passwd_conf = OPT_ARG (SRPPASSWDCONF);
1677 if (HAVE_OPT (PSKPASSWD))
1678 psk_passwd = OPT_ARG (PSKPASSWD);
1680 if (HAVE_OPT(OCSP_RESPONSE))
1681 status_response_ocsp = OPT_ARG(OCSP_RESPONSE);
1685 /* session resuming support */
1687 #define SESSION_ID_SIZE 32
1688 #define SESSION_DATA_SIZE 1024
1690 typedef struct
1692 char session_id[SESSION_ID_SIZE];
1693 unsigned int session_id_size;
1695 char session_data[SESSION_DATA_SIZE];
1696 unsigned int session_data_size;
1697 } CACHE;
1699 static CACHE *cache_db;
1700 int cache_db_ptr = 0;
1702 static void
1703 wrap_db_init (void)
1705 /* allocate cache_db */
1706 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1709 static void
1710 wrap_db_deinit (void)
1714 static int
1715 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1718 if (cache_db == NULL)
1719 return -1;
1721 if (key.size > SESSION_ID_SIZE)
1722 return -1;
1723 if (data.size > SESSION_DATA_SIZE)
1724 return -1;
1726 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1727 cache_db[cache_db_ptr].session_id_size = key.size;
1729 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1730 cache_db[cache_db_ptr].session_data_size = data.size;
1732 cache_db_ptr++;
1733 cache_db_ptr %= ssl_session_cache;
1735 return 0;
1738 static gnutls_datum_t
1739 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1741 gnutls_datum_t res = { NULL, 0 };
1742 int i;
1744 if (cache_db == NULL)
1745 return res;
1747 for (i = 0; i < ssl_session_cache; i++)
1749 if (key.size == cache_db[i].session_id_size &&
1750 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1752 res.size = cache_db[i].session_data_size;
1754 res.data = gnutls_malloc (res.size);
1755 if (res.data == NULL)
1756 return res;
1758 memcpy (res.data, cache_db[i].session_data, res.size);
1760 return res;
1763 return res;
1766 static int
1767 wrap_db_delete (void *dbf, gnutls_datum_t key)
1769 int i;
1771 if (cache_db == NULL)
1772 return -1;
1774 for (i = 0; i < ssl_session_cache; i++)
1776 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1777 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1780 cache_db[i].session_id_size = 0;
1781 cache_db[i].session_data_size = 0;
1783 return 0;
1787 return -1;