2 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 Free Software
4 * Copyright (C) 2001,2002 Paul Sheer
5 * Portions Copyright (C) 2002,2003 Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
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.
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.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* This server is heavily modified for GnuTLS by Nikos Mavrogiannopoulos
24 * (which means it is quite unreadable)
34 #include <sys/types.h>
36 #include <gnutls/gnutls.h>
37 #include <gnutls/extra.h>
38 #include <gnutls/openpgp.h>
40 #include <sys/select.h>
46 /* Gnulib portability files. */
48 #include "version-etc.h"
49 #include "read-file.h"
53 /* konqueror cannot handle sending the page in multiple
57 static int generate = 0;
67 int disable_client_cert;
71 char *srp_passwd_conf;
77 char *x509_dsakeyfile;
78 char *x509_dsacertfile;
81 char *x509_crlfile = NULL;
83 gnutls_datum_t session_ticket_key;
87 /* This is a sample TCP echo server.
88 * This will behave as an http server if any argument in the
89 * command line is present
92 #define SMALL_READ_TEST (2147483647)
94 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
96 #define HTTP_END "</BODY></HTML>\n\n"
98 #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"
99 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
101 #define HTTP_BEGIN HTTP_OK \
104 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
105 "GnuTLS</a></H1></CENTER>\n\n"
107 /* These are global */
108 gnutls_srp_server_credentials_t srp_cred = NULL;
109 gnutls_psk_server_credentials_t psk_cred = NULL;
110 gnutls_anon_server_credentials_t dh_cred = NULL;
111 gnutls_certificate_credentials_t cert_cred = NULL;
115 const int ssl_session_cache = 128;
117 static void wrap_db_init (void);
118 static void wrap_db_deinit (void);
119 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
120 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
121 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
124 #define HTTP_STATE_REQUEST 1
125 #define HTTP_STATE_RESPONSE 2
126 #define HTTP_STATE_CLOSING 3
128 LIST_TYPE_DECLARE (listener_item, char *http_request; char *http_response;
129 int request_length; int response_length;
130 int response_written; int http_state;
131 int listen_socket; int fd;
132 gnutls_session_t tls_session;
137 safe_strerror (int value)
139 const char *ret = gnutls_strerror (value);
146 listener_free (listener_item * j)
149 free (j->http_request);
150 free (j->http_response);
153 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
156 gnutls_deinit (j->tls_session);
161 /* we use primes up to 1024 in this server.
162 * otherwise we should add them here.
165 gnutls_dh_params_t dh_params = NULL;
166 gnutls_rsa_params_t rsa_params = NULL;
169 generate_dh_primes (void)
171 int prime_bits = 768;
173 if (gnutls_dh_params_init (&dh_params) < 0)
175 fprintf (stderr, "Error in dh parameter initialization\n");
179 /* Generate Diffie-Hellman parameters - for use with DHE
180 * kx algorithms. These should be discarded and regenerated
181 * once a week or once a month. Depends on the
182 * security requirements.
185 ("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
189 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
191 fprintf (stderr, "Error in prime generation\n");
199 read_dh_params (void)
203 gnutls_datum_t params;
206 if (gnutls_dh_params_init (&dh_params) < 0)
208 fprintf (stderr, "Error in dh parameter initialization\n");
212 /* read the params file
214 fd = fopen (dh_params_file, "r");
217 fprintf (stderr, "Could not open %s\n", dh_params_file);
221 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
225 params.data = (unsigned char *) tmpdata;
229 gnutls_dh_params_import_pkcs3 (dh_params, ¶ms, GNUTLS_X509_FMT_PEM);
233 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
237 printf ("Read Diffie-Hellman parameters.\n");
242 static char pkcs3[] =
243 "-----BEGIN DH PARAMETERS-----\n"
244 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
245 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
246 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
247 "-----END DH PARAMETERS-----\n";
250 static_dh_params (void)
252 gnutls_datum_t params = { pkcs3, sizeof (pkcs3) };
255 if (gnutls_dh_params_init (&dh_params) < 0)
257 fprintf (stderr, "Error in dh parameter initialization\n");
261 ret = gnutls_dh_params_import_pkcs3 (dh_params, ¶ms,
262 GNUTLS_X509_FMT_PEM);
266 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
270 printf ("Set static Diffie-Hellman parameters, consider --dhparams.\n");
276 get_params (gnutls_session_t session, gnutls_params_type_t type,
277 gnutls_params_st * st)
280 if (type == GNUTLS_PARAMS_RSA_EXPORT)
282 if (rsa_params == NULL)
284 st->params.rsa_export = rsa_params;
286 else if (type == GNUTLS_PARAMS_DH)
288 if (dh_params == NULL)
290 st->params.dh = dh_params;
302 generate_rsa_params (void)
304 if (gnutls_rsa_params_init (&rsa_params) < 0)
306 fprintf (stderr, "Error in rsa parameter initialization\n");
310 /* Generate RSA parameters - for use with RSA-export
311 * cipher suites. These should be discarded and regenerated
312 * once a day, once every 500 transactions etc. Depends on the
313 * security requirements.
315 printf ("Generating temporary RSA parameters. Please wait...\n");
318 if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
320 fprintf (stderr, "Error in rsa parameter generation\n");
327 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
329 static gnutls_session_t
330 initialize_session (void)
332 gnutls_session_t session;
335 gnutls_init (&session, GNUTLS_SERVER);
337 /* allow the use of private ciphersuites.
339 gnutls_handshake_set_private_extensions (session, 1);
343 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
344 gnutls_db_set_remove_function (session, wrap_db_delete);
345 gnutls_db_set_store_function (session, wrap_db_store);
346 gnutls_db_set_ptr (session, NULL);
348 #ifdef ENABLE_SESSION_TICKET
350 gnutls_session_ticket_enable_server (session, &session_ticket_key);
353 if (gnutls_priority_set_direct (session, info.priorities, &err) < 0)
355 fprintf (stderr, "Syntax error at: %s\n", err);
359 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
361 if (srp_cred != NULL)
362 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
364 if (psk_cred != NULL)
365 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
367 if (cert_cred != NULL)
368 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
370 if (disable_client_cert)
371 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
375 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
377 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
383 #include <gnutls/x509.h>
385 static const char DEFAULT_DATA[] =
386 "This is the default message reported by the GnuTLS implementation. "
387 "For more information please visit "
388 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
390 /* Creates html with the current session information.
392 #define tmp_buffer &http_buffer[strlen(http_buffer)]
393 #define tmp_buffer_size len-strlen(http_buffer)
395 peer_print_info (gnutls_session_t session, int *ret_length,
399 unsigned char sesid[32];
400 size_t i, sesid_size;
402 gnutls_kx_algorithm_t kx_alg;
403 size_t len = 20 * 1024 + strlen (header);
404 char *crtinfo = NULL;
409 http_buffer = malloc (len);
410 if (http_buffer == NULL)
413 strcpy (http_buffer, HTTP_BEGIN);
414 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
415 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
418 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
423 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
425 const gnutls_datum_t *cert_list;
426 unsigned int cert_list_size = 0;
428 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
430 for (i = 0; i < cert_list_size; i++)
432 gnutls_x509_crt_t cert;
435 if (gnutls_x509_crt_init (&cert) == 0 &&
436 gnutls_x509_crt_import (cert, &cert_list[i],
437 GNUTLS_X509_FMT_DER) == 0 &&
438 gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &info) == 0)
440 const char *post = "</PRE><P><PRE>";
442 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
446 memcpy (crtinfo + ncrtinfo, info.data, info.size);
447 ncrtinfo += info.size;
448 memcpy (crtinfo + ncrtinfo, post, strlen (post));
449 ncrtinfo += strlen (post);
450 crtinfo[ncrtinfo] = '\0';
451 gnutls_free (info.data);
456 http_buffer = malloc (len);
457 if (http_buffer == NULL)
463 strcpy (http_buffer, HTTP_BEGIN);
465 /* print session_id */
466 gnutls_session_get_id (session, sesid, &sesid_size);
467 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Session ID: <i>");
468 for (i = 0; i < sesid_size; i++)
469 snprintf (tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
470 snprintf (tmp_buffer, tmp_buffer_size, "</i></p>\n");
471 snprintf (tmp_buffer, tmp_buffer_size,
472 "<h5>If your browser supports session resuming, then you should see the "
473 "same session ID, when you press the <b>reload</b> button.</h5>\n");
475 /* Here unlike print_info() we use the kx algorithm to distinguish
476 * the functions to call.
480 size_t dns_size = sizeof (dns);
483 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
485 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Server Name: %s</p>\n", dns);
490 kx_alg = gnutls_kx_get (session);
492 /* print srp specific data */
494 if (kx_alg == GNUTLS_KX_SRP)
496 snprintf (tmp_buffer, tmp_buffer_size, "<p>Connected as user '%s'.</p>\n",
497 gnutls_srp_server_get_username (session));
502 if (kx_alg == GNUTLS_KX_PSK)
504 snprintf (tmp_buffer, tmp_buffer_size, "<p>Connected as user '%s'.</p>\n",
505 gnutls_psk_server_get_username (session));
510 if (kx_alg == GNUTLS_KX_ANON_DH)
512 snprintf (tmp_buffer, tmp_buffer_size,
513 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
514 gnutls_dh_get_prime_bits (session));
518 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
520 snprintf (tmp_buffer, tmp_buffer_size,
521 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
522 gnutls_dh_get_prime_bits (session));
525 /* print session information */
526 strcat (http_buffer, "<P>\n");
528 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
531 snprintf (tmp_buffer, tmp_buffer_size,
532 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
535 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
538 gnutls_certificate_type_get_name (gnutls_certificate_type_get
542 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n",
546 tmp = gnutls_kx_get_name (kx_alg);
549 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
551 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
554 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
556 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
559 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
561 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
564 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
566 tmp = gnutls_cipher_suite_get_name (kx_alg,
567 gnutls_cipher_get (session),
568 gnutls_mac_get (session));
571 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
576 snprintf (tmp_buffer, tmp_buffer_size, "<hr><PRE>%s\n</PRE>\n", crtinfo);
580 snprintf (tmp_buffer, tmp_buffer_size, "<hr><P>Your HTTP header was:<PRE>%s</PRE></P>\n" HTTP_END,
583 *ret_length = strlen (http_buffer);
589 human_addr (const struct sockaddr *sa, socklen_t salen,
590 char *buf, size_t buflen)
592 const char *save_buf = buf;
600 switch (sa->sa_family)
604 snprintf (buf, buflen, "IPv6 ");
609 snprintf (buf, buflen, "IPv4 ");
617 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
624 strncat (buf, " port ", buflen);
630 if (getnameinfo (sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
637 listen_socket (const char *name, int listen_port)
639 struct addrinfo hints, *res, *ptr;
643 listener_item *j = NULL;
645 snprintf (portname, sizeof (portname), "%d", listen_port);
646 memset (&hints, 0, sizeof (hints));
647 hints.ai_socktype = SOCK_STREAM;
648 hints.ai_flags = AI_PASSIVE;
650 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
652 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
656 for (ptr = res; ptr != NULL; ptr = ptr->ai_next)
658 /* Print what we are doing. */
662 fprintf (stderr, "%s listening on %s...",
663 name, human_addr (ptr->ai_addr, ptr->ai_addrlen,
664 topbuf, sizeof (topbuf)));
667 if ((s = socket (ptr->ai_family, ptr->ai_socktype,
668 ptr->ai_protocol)) < 0)
670 perror ("socket() failed");
675 if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
676 (const void *) &yes, sizeof (yes)) < 0)
678 perror ("setsockopt() failed");
684 if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
686 perror ("bind() failed");
690 if (listen (s, 10) < 0)
692 perror ("listen() failed");
696 /* new list entry for the connection */
697 lappend (listener_list);
698 j = listener_list.tail;
699 j->listen_socket = 1;
702 /* Complete earlier message. */
703 fprintf (stderr, "done\n");
715 /* strips \r\n from the end of the string
721 int len = strlen (data);
723 for (i = 0; i < len; i++)
725 if (data[i] == '\r' && data[i + 1] == '\n' && data[i + 1] == 0)
735 get_response (gnutls_session_t session, char *request,
736 char **response, int *response_length)
742 if (strncmp (request, "GET ", 4))
745 if (!(h = strchr (request, '\n')))
749 while (*h == '\r' || *h == '\n')
752 if (!(p = strchr (request + 4, ' ')))
756 /* *response = peer_print_info(session, request+4, h, response_length); */
759 *response = peer_print_info (session, response_length, h);
764 fprintf (stderr, "received: %s\n", request);
765 if (request[0] == request[1] && request[0] == '*')
768 (request, "**REHANDSHAKE**",
769 sizeof ("**REHANDSHAKE**") - 1) == 0)
771 fprintf (stderr, "*** Sending rehandshake request\n");
772 gnutls_rehandshake (session);
775 *response_length = 0;
778 *response = strdup (request);
779 *response_length = ((*response) ? strlen (*response) : 0);
785 *response = strdup (HTTP_UNIMPLEMENTED);
786 *response_length = ((*response) ? strlen (*response) : 0);
789 static void terminate (int sig) __attribute__ ((noreturn));
794 fprintf (stderr, "Exiting via signal %d\n", sig);
800 check_alert (gnutls_session_t session, int ret)
802 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
803 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
805 int last_alert = gnutls_alert_get (session);
806 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
807 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
809 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
811 printf ("* Received alert '%d': %s.\n", last_alert,
812 gnutls_alert_get_name (last_alert));
817 tls_log_func (int level, const char *str)
819 fprintf (stderr, "|<%d>| %s", level, str);
822 static void gaa_parser (int argc, char **argv);
825 main (int argc, char **argv)
831 struct sockaddr_storage client_address;
834 set_program_name (argv[0]);
837 signal (SIGPIPE, SIG_IGN);
838 signal (SIGHUP, SIG_IGN);
839 signal (SIGTERM, terminate);
840 if (signal (SIGINT, terminate) == SIG_IGN)
841 signal (SIGINT, SIG_IGN); /* e.g. background process */
846 gaa_parser (argc, argv);
853 strcpy (name, "HTTP Server");
857 strcpy (name, "Echo Server");
860 if ((ret = gnutls_global_init ()) < 0)
862 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
866 if ((ret = gnutls_global_init_extra ()) < 0)
868 fprintf (stderr, "global_init_extra: %s\n", gnutls_strerror (ret));
875 gnutls_global_set_log_function (tls_log_func);
876 gnutls_global_set_log_level (debug);
878 /* Note that servers must generate parameters for
879 * Diffie-Hellman. See gnutls_dh_params_generate(), and
880 * gnutls_dh_params_set().
884 generate_rsa_params ();
885 generate_dh_primes ();
887 else if (dh_params_file)
896 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
898 fprintf (stderr, "memory error\n");
902 if (x509_cafile != NULL)
904 if ((ret = gnutls_certificate_set_x509_trust_file
905 (cert_cred, x509_cafile, x509ctype)) < 0)
907 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
913 printf ("Processed %d CA certificate(s).\n", ret);
917 if (x509_crlfile != NULL)
919 if ((ret = gnutls_certificate_set_x509_crl_file
920 (cert_cred, x509_crlfile, x509ctype)) < 0)
922 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
928 printf ("Processed %d CRL(s).\n", ret);
933 #ifdef ENABLE_OPENPGP
934 if (pgp_keyring != NULL)
937 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring,
938 GNUTLS_OPENPGP_FMT_BASE64);
941 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
946 if (pgp_certfile != NULL)
948 if (info.pgp_subkey != NULL)
949 ret = gnutls_certificate_set_openpgp_key_file2
950 (cert_cred, pgp_certfile, pgp_keyfile, info.pgp_subkey,
951 GNUTLS_OPENPGP_FMT_BASE64);
953 ret = gnutls_certificate_set_openpgp_key_file
954 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64);
959 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
960 ret, pgp_certfile, pgp_keyfile);
966 if (x509_certfile != NULL)
967 if ((ret = gnutls_certificate_set_x509_key_file
968 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
971 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
976 if (x509_dsacertfile != NULL)
977 if ((ret = gnutls_certificate_set_x509_key_file
978 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
980 fprintf (stderr, "Error reading '%s' or '%s'\n",
981 x509_dsacertfile, x509_dsakeyfile);
986 gnutls_certificate_set_params_function (cert_cred, get_params);
987 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
988 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
991 /* this is a password file (created with the included srpcrypt utility)
992 * Read README.crypt prior to using SRP.
995 if (srp_passwd != NULL)
997 gnutls_srp_allocate_server_credentials (&srp_cred);
1000 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1001 srp_passwd_conf)) < 0)
1003 /* only exit is this function is not disabled
1005 fprintf (stderr, "Error while setting SRP parameters\n");
1011 /* this is a password file
1014 if (psk_passwd != NULL)
1016 gnutls_psk_allocate_server_credentials (&psk_cred);
1019 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1021 /* only exit is this function is not disabled
1023 fprintf (stderr, "Error while setting PSK parameters\n");
1029 ret = gnutls_psk_set_server_credentials_hint (psk_cred,
1033 fprintf (stderr, "Error setting PSK identity hint.\n");
1038 gnutls_psk_set_server_params_function (psk_cred, get_params);
1043 gnutls_anon_allocate_server_credentials (&dh_cred);
1044 gnutls_anon_set_server_params_function (dh_cred, get_params);
1046 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1049 #ifdef ENABLE_SESSION_TICKET
1051 gnutls_session_ticket_key_generate (&session_ticket_key);
1054 if (listen_socket (name, port) < 0)
1069 /* flag which connections we are reading or writing to within the fd sets */
1070 lloopstart (listener_list, j)
1074 val = fcntl (j->fd, F_GETFL, 0);
1075 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1082 if (j->listen_socket)
1084 FD_SET (j->fd, &rd);
1087 if (j->http_state == HTTP_STATE_REQUEST)
1089 FD_SET (j->fd, &rd);
1092 if (j->http_state == HTTP_STATE_RESPONSE)
1094 FD_SET (j->fd, &wr);
1098 lloopend (listener_list, j);
1100 /* core operation */
1101 n = select (n + 1, &rd, &wr, NULL, NULL);
1102 if (n == -1 && errno == EINTR)
1106 perror ("select()");
1110 /* read or write to each connection as indicated by select()'s return argument */
1111 lloopstart (listener_list, j)
1114 /* a new connection has arrived */
1115 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
1117 gnutls_session_t tls_session;
1119 tls_session = initialize_session ();
1121 calen = sizeof (client_address);
1122 memset (&client_address, 0, calen);
1123 accept_fd = accept (j->fd, (struct sockaddr *) &client_address,
1128 perror ("accept()");
1135 /* new list entry for the connection */
1136 lappend (listener_list);
1137 j = listener_list.tail;
1138 j->http_request = (char *) strdup ("");
1139 j->http_state = HTTP_STATE_REQUEST;
1142 j->tls_session = tls_session;
1143 gnutls_transport_set_ptr (tls_session,
1144 (gnutls_transport_ptr_t)
1145 gl_fd_to_handle (accept_fd));
1146 j->handshake_ok = 0;
1152 ctt[strlen (ctt) - 1] = 0;
1154 printf ("\n* Accepted connection from %s on %s\n",
1155 human_addr ((struct sockaddr *)
1156 &client_address, calen, topbuf,
1157 sizeof (topbuf)), ctt);
1162 if (FD_ISSET (j->fd, &rd) && !j->listen_socket)
1164 /* read partial GET request */
1168 if (j->handshake_ok == 0)
1170 r = gnutls_handshake (j->tls_session);
1171 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1173 check_alert (j->tls_session, r);
1176 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1178 check_alert (j->tls_session, r);
1179 fprintf (stderr, "Error in handshake\n");
1185 gnutls_alert_send_appropriate (j->tls_session, r);
1187 while (ret == GNUTLS_E_AGAIN
1188 || ret == GNUTLS_E_INTERRUPTED);
1189 j->http_state = HTTP_STATE_CLOSING;
1193 if (gnutls_session_is_resumed (j->tls_session) != 0
1195 printf ("*** This is a resumed session\n");
1199 printf ("\n* Successful handshake from %s\n",
1200 human_addr ((struct sockaddr *)
1201 &client_address, calen, topbuf,
1203 print_info (j->tls_session, NULL, 1);
1205 j->handshake_ok = 1;
1209 if (j->handshake_ok == 1)
1211 r = gnutls_record_recv (j->tls_session, buf,
1212 MIN (1024, SMALL_READ_TEST));
1213 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1219 if (r == GNUTLS_E_REHANDSHAKE)
1221 fprintf (stderr, "*** Received hello message\n");
1224 r = gnutls_handshake (j->tls_session);
1226 while (r == GNUTLS_E_INTERRUPTED
1227 || r == GNUTLS_E_AGAIN);
1233 ret = gnutls_alert_send_appropriate
1234 (j->tls_session, r);
1236 while (ret == GNUTLS_E_AGAIN
1237 || ret == GNUTLS_E_INTERRUPTED);
1240 j->http_state = HTTP_STATE_CLOSING;
1245 j->http_state = HTTP_STATE_CLOSING;
1246 if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1248 check_alert (j->tls_session, r);
1249 fprintf (stderr, "Error while receiving data\n");
1257 realloc (j->http_request, j->request_length + r + 1);
1258 if (j->http_request != NULL)
1260 memcpy (j->http_request + j->request_length, buf, r);
1261 j->request_length += r;
1262 j->http_request[j->request_length] = '\0';
1265 j->http_state = HTTP_STATE_CLOSING;
1268 /* check if we have a full HTTP header */
1270 j->http_response = NULL;
1271 if (j->http_request != NULL)
1273 if ((http == 0 && strchr (j->http_request, '\n'))
1274 || strstr (j->http_request, "\r\n\r\n")
1275 || strstr (j->http_request, "\n\n"))
1277 get_response (j->tls_session, j->http_request,
1278 &j->http_response, &j->response_length);
1279 j->http_state = HTTP_STATE_RESPONSE;
1280 j->response_written = 0;
1285 if (FD_ISSET (j->fd, &wr))
1287 /* write partial response request */
1290 if (j->handshake_ok == 0)
1292 r = gnutls_handshake (j->tls_session);
1293 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1295 check_alert (j->tls_session, r);
1298 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1302 j->http_state = HTTP_STATE_CLOSING;
1303 check_alert (j->tls_session, r);
1304 fprintf (stderr, "Error in handshake\n");
1310 gnutls_alert_send_appropriate (j->tls_session, r);
1312 while (ret == GNUTLS_E_AGAIN);
1316 if (gnutls_session_is_resumed (j->tls_session) != 0
1318 printf ("*** This is a resumed session\n");
1321 printf ("- connection from %s\n",
1322 human_addr ((struct sockaddr *)
1323 &client_address, calen, topbuf,
1326 print_info (j->tls_session, NULL, 1);
1328 j->handshake_ok = 1;
1332 if (j->handshake_ok == 1 && j->http_response != NULL)
1334 /* FIXME if j->http_response == NULL? */
1335 r = gnutls_record_send (j->tls_session,
1337 j->response_written,
1338 MIN (j->response_length -
1339 j->response_written,
1341 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1348 j->http_state = HTTP_STATE_CLOSING;
1351 j->http_state = HTTP_STATE_REQUEST;
1352 free (j->http_response);
1353 j->response_length = 0;
1354 j->request_length = 0;
1355 j->http_request[0] = 0;
1360 fprintf (stderr, "Error while sending data\n");
1363 check_alert (j->tls_session, r);
1367 j->response_written += r;
1368 /* check if we have written a complete response */
1369 if (j->response_written == j->response_length)
1372 j->http_state = HTTP_STATE_CLOSING;
1375 j->http_state = HTTP_STATE_REQUEST;
1376 free (j->http_response);
1377 j->response_length = 0;
1378 j->request_length = 0;
1379 j->http_request[0] = 0;
1386 j->request_length = 0;
1387 j->http_request[0] = 0;
1388 j->http_state = HTTP_STATE_REQUEST;
1392 lloopend (listener_list, j);
1394 /* loop through all connections, closing those that are in error */
1395 lloopstart (listener_list, j)
1397 if (j->http_state == HTTP_STATE_CLOSING)
1399 ldeleteinc (listener_list, j);
1402 lloopend (listener_list, j);
1406 gnutls_certificate_free_credentials (cert_cred);
1410 gnutls_srp_free_server_credentials (srp_cred);
1415 gnutls_psk_free_server_credentials (psk_cred);
1419 gnutls_anon_free_server_credentials (dh_cred);
1422 #ifdef ENABLE_SESSION_TICKET
1424 gnutls_free (session_ticket_key.data);
1429 gnutls_global_deinit ();
1436 gaa_parser (int argc, char **argv)
1438 if (gaa (argc, argv, &info) != -1)
1441 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1445 disable_client_cert = info.disable_client_cert;
1446 require_cert = info.require_cert;
1448 verbose = info.quiet;
1450 noticket = info.noticket;
1457 if (info.fmtder == 0)
1458 x509ctype = GNUTLS_X509_FMT_PEM;
1460 x509ctype = GNUTLS_X509_FMT_DER;
1462 if (info.generate == 0)
1467 dh_params_file = info.dh_params_file;
1471 x509_certfile = info.x509_certfile;
1472 x509_keyfile = info.x509_keyfile;
1473 x509_dsacertfile = info.x509_dsacertfile;
1474 x509_dsakeyfile = info.x509_dsakeyfile;
1475 x509_cafile = info.x509_cafile;
1476 x509_crlfile = info.x509_crlfile;
1477 pgp_certfile = info.pgp_certfile;
1478 pgp_keyfile = info.pgp_keyfile;
1479 srp_passwd = info.srp_passwd;
1480 srp_passwd_conf = info.srp_passwd_conf;
1482 psk_passwd = info.psk_passwd;
1484 pgp_keyring = info.pgp_keyring;
1487 extern void serv_version (void);
1492 const char *p = PACKAGE_NAME;
1493 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
1495 version_etc (stdout, program_name, p, gnutls_check_version (NULL),
1496 "Nikos Mavrogiannopoulos", (char *) NULL);
1499 /* session resuming support */
1501 #define SESSION_ID_SIZE 32
1502 #define SESSION_DATA_SIZE 1024
1506 char session_id[SESSION_ID_SIZE];
1507 unsigned int session_id_size;
1509 char session_data[SESSION_DATA_SIZE];
1510 unsigned int session_data_size;
1513 static CACHE *cache_db;
1514 int cache_db_ptr = 0;
1519 /* allocate cache_db */
1520 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1524 wrap_db_deinit (void)
1529 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1532 if (cache_db == NULL)
1535 if (key.size > SESSION_ID_SIZE)
1537 if (data.size > SESSION_DATA_SIZE)
1540 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1541 cache_db[cache_db_ptr].session_id_size = key.size;
1543 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1544 cache_db[cache_db_ptr].session_data_size = data.size;
1547 cache_db_ptr %= ssl_session_cache;
1552 static gnutls_datum_t
1553 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1555 gnutls_datum_t res = { NULL, 0 };
1558 if (cache_db == NULL)
1561 for (i = 0; i < ssl_session_cache; i++)
1563 if (key.size == cache_db[i].session_id_size &&
1564 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1566 res.size = cache_db[i].session_data_size;
1568 res.data = gnutls_malloc (res.size);
1569 if (res.data == NULL)
1572 memcpy (res.data, cache_db[i].session_data, res.size);
1581 wrap_db_delete (void *dbf, gnutls_datum_t key)
1585 if (cache_db == NULL)
1588 for (i = 0; i < ssl_session_cache; i++)
1590 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1591 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1594 cache_db[i].session_id_size = 0;
1595 cache_db[i].session_data_size = 0;