Add announcement message.
[gnutls.git] / src / serv.c
blob79859c74697b432a54b7711670144e089e004ee4
1 /*
2 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 Free Software
3 * Foundation, Inc.
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)
27 #include <config.h>
29 #include "common.h"
30 #include "serv-gaa.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <string.h>
36 #include <gnutls/gnutls.h>
37 #include <gcrypt.h>
38 #include <gnutls/extra.h>
39 #include <gnutls/openpgp.h>
40 #include <sys/time.h>
41 #include <sys/select.h>
42 #include <fcntl.h>
43 #include <list.h>
44 #include <netdb.h>
45 #include <error.h>
47 /* Gnulib portability files. */
48 #include "progname.h"
49 #include "version-etc.h"
50 #include "read-file.h"
51 #include "minmax.h"
52 #include "sockets.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 port = 0;
61 static int x509ctype;
62 static int debug;
64 int verbose;
65 static int nodb;
66 static int noticket;
67 int require_cert;
68 int disable_client_cert;
70 char *psk_passwd;
71 char *srp_passwd;
72 char *srp_passwd_conf;
73 char *pgp_keyring;
74 char *pgp_keyfile;
75 char *pgp_certfile;
76 char *x509_keyfile;
77 char *x509_certfile;
78 char *x509_dsakeyfile;
79 char *x509_dsacertfile;
80 char *x509_cafile;
81 char *dh_params_file;
82 char *x509_crlfile = NULL;
84 gnutls_datum_t session_ticket_key;
86 /* end of globals */
88 /* This is a sample TCP echo server.
89 * This will behave as an http server if any argument in the
90 * command line is present
93 #define SMALL_READ_TEST (2147483647)
95 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
97 #define HTTP_END "</BODY></HTML>\n\n"
99 #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"
100 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
102 #define HTTP_BEGIN HTTP_OK \
103 "\n" \
104 "<HTML><BODY>\n" \
105 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
106 "GNUTLS</a></H1></CENTER>\n\n"
108 /* These are global */
109 gnutls_srp_server_credentials_t srp_cred = NULL;
110 gnutls_psk_server_credentials_t psk_cred = NULL;
111 gnutls_anon_server_credentials_t dh_cred = NULL;
112 gnutls_certificate_credentials_t cert_cred = NULL;
114 static gaainfo info;
116 const int ssl_session_cache = 128;
118 static void wrap_db_init (void);
119 static void wrap_db_deinit (void);
120 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
121 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
122 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
125 #define HTTP_STATE_REQUEST 1
126 #define HTTP_STATE_RESPONSE 2
127 #define HTTP_STATE_CLOSING 3
129 LIST_TYPE_DECLARE (listener_item, char *http_request;
130 char *http_response; int request_length;
131 int response_length; int response_written;
132 int http_state; int listen_socket;
133 int fd; gnutls_session_t tls_session; int handshake_ok;);
135 static const char *
136 safe_strerror (int value)
138 const char *ret = gnutls_strerror (value);
139 if (ret == NULL)
140 ret = str_unknown;
141 return ret;
144 static void
145 listener_free (listener_item * j)
148 free (j->http_request);
149 free (j->http_response);
150 if (j->fd >= 0)
152 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
153 shutdown (j->fd, 2);
154 close (j->fd);
155 gnutls_deinit (j->tls_session);
160 /* we use primes up to 1024 in this server.
161 * otherwise we should add them here.
164 gnutls_dh_params_t dh_params = NULL;
165 gnutls_rsa_params_t rsa_params = NULL;
167 static int
168 generate_dh_primes (void)
170 int prime_bits = 768;
172 if (gnutls_dh_params_init (&dh_params) < 0)
174 fprintf (stderr, "Error in dh parameter initialization\n");
175 exit (1);
178 /* Generate Diffie-Hellman parameters - for use with DHE
179 * kx algorithms. These should be discarded and regenerated
180 * once a week or once a month. Depends on the
181 * security requirements.
183 printf
184 ("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
185 prime_bits);
186 fflush (stdout);
188 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
190 fprintf (stderr, "Error in prime generation\n");
191 exit (1);
194 return 0;
197 static void
198 read_dh_params (void)
200 char tmpdata[2048];
201 int size;
202 gnutls_datum_t params;
203 FILE *fd;
205 if (gnutls_dh_params_init (&dh_params) < 0)
207 fprintf (stderr, "Error in dh parameter initialization\n");
208 exit (1);
211 /* read the params file
213 fd = fopen (dh_params_file, "r");
214 if (fd == NULL)
216 fprintf (stderr, "Could not open %s\n", dh_params_file);
217 exit (1);
220 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
221 tmpdata[size] = 0;
222 fclose (fd);
224 params.data = (unsigned char *) tmpdata;
225 params.size = size;
227 size =
228 gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
230 if (size < 0)
232 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
233 exit (1);
236 printf ("Read Diffie-Hellman parameters.\n");
237 fflush (stdout);
241 static char pkcs3[] =
242 "-----BEGIN DH PARAMETERS-----\n"
243 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
244 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
245 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
246 "-----END DH PARAMETERS-----\n";
248 static int
249 static_dh_params (void)
251 gnutls_datum_t params = { pkcs3, sizeof (pkcs3) };
252 int ret;
254 if (gnutls_dh_params_init (&dh_params) < 0)
256 fprintf (stderr, "Error in dh parameter initialization\n");
257 exit (1);
260 ret = gnutls_dh_params_import_pkcs3 (dh_params, &params,
261 GNUTLS_X509_FMT_PEM);
263 if (ret < 0)
265 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
266 exit (1);
269 printf ("Set static Diffie-Hellman parameters, consider --dhparams.\n");
271 return 0;
274 static int
275 get_params (gnutls_session_t session, gnutls_params_type_t type,
276 gnutls_params_st * st)
279 if (type == GNUTLS_PARAMS_RSA_EXPORT)
281 if (rsa_params == NULL)
282 return -1;
283 st->params.rsa_export = rsa_params;
285 else if (type == GNUTLS_PARAMS_DH)
287 if (dh_params == NULL)
288 return -1;
289 st->params.dh = dh_params;
291 else
292 return -1;
294 st->type = type;
295 st->deinit = 0;
297 return 0;
300 static int
301 generate_rsa_params (void)
303 if (gnutls_rsa_params_init (&rsa_params) < 0)
305 fprintf (stderr, "Error in rsa parameter initialization\n");
306 exit (1);
309 /* Generate RSA parameters - for use with RSA-export
310 * cipher suites. These should be discarded and regenerated
311 * once a day, once every 500 transactions etc. Depends on the
312 * security requirements.
314 printf ("Generating temporary RSA parameters. Please wait...\n");
315 fflush (stdout);
317 if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
319 fprintf (stderr, "Error in rsa parameter generation\n");
320 exit (1);
323 return 0;
326 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
328 static int protocol_priority[PRI_MAX];
329 static int kx_priority[PRI_MAX];
330 static int cipher_priority[PRI_MAX];
331 static int comp_priority[PRI_MAX];
332 static int mac_priority[PRI_MAX];
333 static int cert_type_priority[PRI_MAX];
335 #if ENABLE_OPRFI
337 oprfi_callback (gnutls_session_t session,
338 void *userdata,
339 size_t oprfi_len,
340 const unsigned char *in_oprfi, unsigned char *out_oprfi)
342 size_t ourlen = strlen (info.opaque_prf_input);
343 size_t i;
345 printf ("- Received Opaque PRF data of %d bytes\n", oprfi_len);
346 printf (" data: ");
347 for (i = 0; i < oprfi_len; i++)
348 printf ("%02x", in_oprfi[i]);
349 printf ("\n");
351 memset (out_oprfi, 0, oprfi_len);
352 strncpy (out_oprfi, info.opaque_prf_input, oprfi_len);
354 return 0;
356 #endif
358 static gnutls_session_t
359 initialize_session (void)
361 gnutls_session_t session;
362 const char *err;
364 gnutls_init (&session, GNUTLS_SERVER);
366 /* allow the use of private ciphersuites.
368 gnutls_handshake_set_private_extensions (session, 1);
370 if (nodb == 0)
372 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
373 gnutls_db_set_remove_function (session, wrap_db_delete);
374 gnutls_db_set_store_function (session, wrap_db_store);
375 gnutls_db_set_ptr (session, NULL);
377 #ifdef ENABLE_SESSION_TICKET
378 if (noticket == 0)
379 gnutls_session_ticket_enable_server (session, &session_ticket_key);
380 #endif
382 if (gnutls_priority_set_direct (session, info.priorities, &err) < 0)
384 fprintf (stderr, "Syntax error at: %s\n", err);
385 exit (1);
388 if (cipher_priority[0])
389 gnutls_cipher_set_priority (session, cipher_priority);
390 if (comp_priority[0])
391 gnutls_compression_set_priority (session, comp_priority);
392 if (kx_priority[0])
393 gnutls_kx_set_priority (session, kx_priority);
394 if (protocol_priority[0])
395 gnutls_protocol_set_priority (session, protocol_priority);
396 if (mac_priority[0])
397 gnutls_mac_set_priority (session, mac_priority);
398 if (cert_type_priority[0])
399 gnutls_certificate_type_set_priority (session, cert_type_priority);
401 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
403 if (srp_cred != NULL)
404 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
406 if (psk_cred != NULL)
407 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
409 if (cert_cred != NULL)
410 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
412 if (disable_client_cert)
413 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
414 else
416 if (require_cert)
417 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
418 else
419 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
422 #ifdef ENABLE_OPRFI
423 if (info.opaque_prf_input)
424 gnutls_oprfi_enable_server (session, oprfi_callback, NULL);
425 #endif
427 return session;
430 #include <gnutls/x509.h>
432 static const char DEFAULT_DATA[] =
433 "This is the default message reported by the GnuTLS implementation. "
434 "For more information please visit "
435 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
437 /* Creates html with the current session information.
439 #define tmp2 &http_buffer[strlen(http_buffer)]
440 static char *
441 peer_print_info (gnutls_session_t session, int *ret_length,
442 const char *header)
444 const char *tmp;
445 unsigned char sesid[32];
446 size_t i, sesid_size;
447 char *http_buffer;
448 gnutls_kx_algorithm_t kx_alg;
449 size_t len = 5 * 1024 + strlen (header);
450 char *crtinfo = NULL;
451 size_t ncrtinfo = 0;
453 if (verbose != 0)
455 http_buffer = malloc (len);
456 if (http_buffer == NULL)
457 return NULL;
459 strcpy (http_buffer, HTTP_BEGIN);
460 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
461 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
462 HTTP_END);
463 *ret_length =
464 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
465 return http_buffer;
469 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
471 const gnutls_datum_t *cert_list;
472 unsigned int cert_list_size = 0;
474 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
476 for (i = 0; i < cert_list_size; i++)
478 gnutls_x509_crt_t cert;
479 gnutls_datum_t info;
481 if (gnutls_x509_crt_init (&cert) == 0 &&
482 gnutls_x509_crt_import (cert, &cert_list[i],
483 GNUTLS_X509_FMT_DER) == 0 &&
484 gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &info) == 0)
486 const char *post = "</PRE><P><PRE>";
488 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
489 strlen (post) + 1);
490 if (crtinfo == NULL)
491 return NULL;
492 memcpy (crtinfo + ncrtinfo, info.data, info.size);
493 ncrtinfo += info.size;
494 memcpy (crtinfo + ncrtinfo, post, strlen (post));
495 ncrtinfo += strlen (post);
496 crtinfo[ncrtinfo] = '\0';
497 gnutls_free (info.data);
502 http_buffer = malloc (len);
503 if (http_buffer == NULL)
505 free(crtinfo);
506 return NULL;
509 strcpy (http_buffer, HTTP_BEGIN);
511 /* print session_id */
512 gnutls_session_get_id (session, sesid, &sesid_size);
513 sprintf (tmp2, "\n<p>Session ID: <i>");
514 for (i = 0; i < sesid_size; i++)
515 sprintf (tmp2, "%.2X", sesid[i]);
516 sprintf (tmp2, "</i></p>\n");
517 sprintf (tmp2,
518 "<h5>If your browser supports session resuming, then you should see the "
519 "same session ID, when you press the <b>reload</b> button.</h5>\n");
521 /* Here unlike print_info() we use the kx algorithm to distinguish
522 * the functions to call.
525 char dns[256];
526 size_t dns_size = sizeof (dns);
527 unsigned int type;
529 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
531 sprintf (tmp2, "\n<p>Server Name: %s</p>\n", dns);
536 kx_alg = gnutls_kx_get (session);
538 /* print srp specific data */
539 #ifdef ENABLE_SRP
540 if (kx_alg == GNUTLS_KX_SRP)
542 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
543 gnutls_srp_server_get_username (session));
545 #endif
547 #ifdef ENABLE_PSK
548 if (kx_alg == GNUTLS_KX_PSK)
550 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
551 gnutls_psk_server_get_username (session));
553 #endif
555 #ifdef ENABLE_ANON
556 if (kx_alg == GNUTLS_KX_ANON_DH)
558 sprintf (tmp2,
559 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
560 gnutls_dh_get_prime_bits (session));
562 #endif
564 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
566 sprintf (tmp2,
567 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
568 gnutls_dh_get_prime_bits (session));
571 /* print session information */
572 strcat (http_buffer, "<P>\n");
574 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
575 if (tmp == NULL)
576 tmp = str_unknown;
577 sprintf (tmp2,
578 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
579 tmp);
581 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
583 tmp =
584 gnutls_certificate_type_get_name (gnutls_certificate_type_get
585 (session));
586 if (tmp == NULL)
587 tmp = str_unknown;
588 sprintf (tmp2, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
591 tmp = gnutls_kx_get_name (kx_alg);
592 if (tmp == NULL)
593 tmp = str_unknown;
594 sprintf (tmp2, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
596 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
597 if (tmp == NULL)
598 tmp = str_unknown;
599 sprintf (tmp2, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
601 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
602 if (tmp == NULL)
603 tmp = str_unknown;
604 sprintf (tmp2, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
606 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
607 if (tmp == NULL)
608 tmp = str_unknown;
609 sprintf (tmp2, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
611 tmp = gnutls_cipher_suite_get_name (kx_alg,
612 gnutls_cipher_get (session),
613 gnutls_mac_get (session));
614 if (tmp == NULL)
615 tmp = str_unknown;
616 sprintf (tmp2, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
617 tmp);
619 if (crtinfo)
621 strcat (http_buffer, "<hr><PRE>");
622 strcat (http_buffer, crtinfo);
623 strcat (http_buffer, "\n</PRE>\n");
624 free(crtinfo);
627 strcat (http_buffer, "<hr><P>Your HTTP header was:<PRE>");
628 strcat (http_buffer, header);
629 strcat (http_buffer, "</PRE></P>");
631 strcat (http_buffer, "\n" HTTP_END);
633 *ret_length = strlen (http_buffer);
635 return http_buffer;
638 static const char *
639 human_addr (const struct sockaddr *sa, socklen_t salen,
640 char *buf, size_t buflen)
642 const char *save_buf = buf;
643 size_t l;
645 if (!buf || !buflen)
646 return NULL;
648 *buf = '\0';
650 switch (sa->sa_family)
652 #if HAVE_IPV6
653 case AF_INET6:
654 snprintf (buf, buflen, "IPv6 ");
655 break;
656 #endif
658 case AF_INET:
659 snprintf (buf, buflen, "IPv4 ");
660 break;
663 l = strlen (buf);
664 buf += l;
665 buflen -= l;
667 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
668 return NULL;
670 l = strlen (buf);
671 buf += l;
672 buflen -= l;
674 strncat (buf, " port ", buflen);
676 l = strlen (buf);
677 buf += l;
678 buflen -= l;
680 if (getnameinfo (sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
681 return NULL;
683 return save_buf;
686 static int
687 listen_socket (const char *name, int listen_port)
689 struct addrinfo hints, *res, *ptr;
690 char portname[6];
691 int s;
692 int yes;
693 listener_item *j = NULL;
695 snprintf (portname, sizeof (portname), "%d", listen_port);
696 memset (&hints, 0, sizeof (hints));
697 hints.ai_socktype = SOCK_STREAM;
698 hints.ai_flags = AI_PASSIVE;
700 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
702 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
703 return -1;
706 for (ptr = res; ptr != NULL; ptr = ptr->ai_next)
708 /* Print what we are doing. */
710 char topbuf[512];
712 fprintf (stderr, "%s listening on %s...",
713 name, human_addr (ptr->ai_addr, ptr->ai_addrlen,
714 topbuf, sizeof (topbuf)));
717 if ((s = socket (ptr->ai_family, ptr->ai_socktype,
718 ptr->ai_protocol)) < 0)
720 perror ("socket() failed");
721 continue;
724 yes = 1;
725 if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
726 (const void *) &yes, sizeof (yes)) < 0)
728 perror ("setsockopt() failed");
729 failed:
730 close (s);
731 continue;
734 if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
736 perror ("bind() failed");
737 goto failed;
740 if (listen (s, 10) < 0)
742 perror ("listen() failed");
743 goto failed;
746 /* new list entry for the connection */
747 lappend (listener_list);
748 j = listener_list.tail;
749 j->listen_socket = 1;
750 j->fd = s;
752 /* Complete earlier message. */
753 fprintf (stderr, "done\n");
756 fflush (stderr);
758 freeaddrinfo (res);
759 if (!j)
760 return -1;
762 return 0;
765 static void
766 get_response (gnutls_session_t session, char *request,
767 char **response, int *response_length)
769 char *p, *h;
771 if (http != 0)
773 if (strncmp (request, "GET ", 4))
774 goto unimplemented;
776 if (!(h = strchr (request, '\n')))
777 goto unimplemented;
779 *h++ = '\0';
780 while (*h == '\r' || *h == '\n')
781 h++;
783 if (!(p = strchr (request + 4, ' ')))
784 goto unimplemented;
785 *p = '\0';
787 /* *response = peer_print_info(session, request+4, h, response_length); */
788 if (http != 0)
790 *response = peer_print_info (session, response_length, h);
792 else
794 fprintf(stderr, "received: %s\n", request);
795 if (request[0] == request[1] && request[0] == '*')
797 if (strncmp(request, "**REHANDSHAKE**", sizeof("**REHANDSHAKE**")-1)==0)
799 fprintf(stderr, "*** Sending rehandshake request\n");
800 gnutls_rehandshake(session);
802 *response = NULL;
803 *response_length = 0;
804 return;
806 *response = strdup (request);
807 *response_length = ((*response) ? strlen (*response) : 0);
810 return;
812 unimplemented:
813 *response = strdup (HTTP_UNIMPLEMENTED);
814 *response_length = ((*response) ? strlen (*response) : 0);
817 static void terminate (int sig) __attribute__ ((noreturn));
819 static void
820 terminate (int sig)
822 fprintf (stderr, "Exiting via signal %d\n", sig);
823 exit (1);
827 static void
828 check_alert (gnutls_session_t session, int ret)
830 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
831 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
833 int last_alert = gnutls_alert_get (session);
834 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
835 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
836 printf
837 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
838 else
839 printf ("* Received alert '%d': %s.\n", last_alert,
840 gnutls_alert_get_name (last_alert));
844 static void
845 tls_log_func (int level, const char *str)
847 fprintf (stderr, "|<%d>| %s", level, str);
850 static void gaa_parser (int argc, char **argv);
853 main (int argc, char **argv)
855 int ret, n;
856 char topbuf[512];
857 char name[256];
858 int accept_fd;
859 struct sockaddr_storage client_address;
860 socklen_t calen;
862 set_program_name (argv[0]);
864 #ifdef gcry_fips_mode_active
865 /* Libgcrypt manual says that gcry_version_check must be called
866 before calling gcry_fips_mode_active. */
867 gcry_check_version (NULL);
868 if (gcry_fips_mode_active ())
870 ret = gnutls_register_md5_handler ();
871 if (ret)
872 fprintf (stderr, "gnutls_register_md5_handler: %s\n",
873 gnutls_strerror (ret));
875 #endif
877 #ifndef _WIN32
878 signal (SIGPIPE, SIG_IGN);
879 signal (SIGHUP, SIG_IGN);
880 signal (SIGTERM, terminate);
881 if (signal (SIGINT, terminate) == SIG_IGN)
882 signal (SIGINT, SIG_IGN); /* e.g. background process */
883 #endif
885 sockets_init ();
887 gaa_parser (argc, argv);
889 if (nodb == 0)
890 wrap_db_init ();
892 if (http == 1)
894 strcpy (name, "HTTP Server");
896 else
898 strcpy (name, "Echo Server");
901 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
903 if ((ret = gnutls_global_init ()) < 0)
905 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
906 exit (1);
909 if ((ret = gnutls_global_init_extra ()) < 0)
911 fprintf (stderr, "global_init_extra: %s\n", gnutls_strerror (ret));
912 exit (1);
915 gnutls_global_set_log_function (tls_log_func);
916 gnutls_global_set_log_level (debug);
918 /* Note that servers must generate parameters for
919 * Diffie-Hellman. See gnutls_dh_params_generate(), and
920 * gnutls_dh_params_set().
922 if (generate != 0)
924 generate_rsa_params ();
925 generate_dh_primes ();
927 else if (dh_params_file)
929 read_dh_params ();
931 else
933 static_dh_params ();
936 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
938 fprintf (stderr, "memory error\n");
939 exit (1);
942 if (x509_cafile != NULL)
944 if ((ret = gnutls_certificate_set_x509_trust_file
945 (cert_cred, x509_cafile, x509ctype)) < 0)
947 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
948 GERR (ret);
949 exit (1);
951 else
953 printf ("Processed %d CA certificate(s).\n", ret);
956 #ifdef ENABLE_PKI
957 if (x509_crlfile != NULL)
959 if ((ret = gnutls_certificate_set_x509_crl_file
960 (cert_cred, x509_crlfile, x509ctype)) < 0)
962 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
963 GERR (ret);
964 exit (1);
966 else
968 printf ("Processed %d CRL(s).\n", ret);
971 #endif
973 #ifdef ENABLE_OPENPGP
974 if (pgp_keyring != NULL)
976 ret =
977 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring,
978 GNUTLS_OPENPGP_FMT_BASE64);
979 if (ret < 0)
981 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
982 GERR (ret);
986 if (pgp_certfile != NULL)
988 if (info.pgp_subkey != NULL)
989 ret = gnutls_certificate_set_openpgp_key_file2
990 (cert_cred, pgp_certfile, pgp_keyfile, info.pgp_subkey,
991 GNUTLS_OPENPGP_FMT_BASE64);
992 else
993 ret = gnutls_certificate_set_openpgp_key_file
994 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64);
996 if (ret < 0)
998 fprintf (stderr,
999 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1000 ret, pgp_certfile, pgp_keyfile);
1001 GERR (ret);
1004 #endif
1006 if (x509_certfile != NULL)
1007 if ((ret = gnutls_certificate_set_x509_key_file
1008 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
1010 fprintf (stderr,
1011 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1012 GERR (ret);
1013 exit (1);
1016 if (x509_dsacertfile != NULL)
1017 if ((ret = gnutls_certificate_set_x509_key_file
1018 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1020 fprintf (stderr, "Error reading '%s' or '%s'\n",
1021 x509_dsacertfile, x509_dsakeyfile);
1022 GERR (ret);
1023 exit (1);
1026 gnutls_certificate_set_params_function (cert_cred, get_params);
1027 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1028 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1031 /* this is a password file (created with the included srpcrypt utility)
1032 * Read README.crypt prior to using SRP.
1034 #ifdef ENABLE_SRP
1035 if (srp_passwd != NULL)
1037 gnutls_srp_allocate_server_credentials (&srp_cred);
1039 if ((ret =
1040 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1041 srp_passwd_conf)) < 0)
1043 /* only exit is this function is not disabled
1045 fprintf (stderr, "Error while setting SRP parameters\n");
1046 GERR (ret);
1049 #endif
1051 /* this is a password file
1053 #ifdef ENABLE_PSK
1054 if (psk_passwd != NULL)
1056 gnutls_psk_allocate_server_credentials (&psk_cred);
1058 if ((ret =
1059 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1061 /* only exit is this function is not disabled
1063 fprintf (stderr, "Error while setting PSK parameters\n");
1064 GERR (ret);
1067 if (info.psk_hint)
1069 ret = gnutls_psk_set_server_credentials_hint (psk_cred,
1070 info.psk_hint);
1071 if (ret)
1073 fprintf (stderr, "Error setting PSK identity hint.\n");
1074 GERR (ret);
1078 gnutls_psk_set_server_params_function (psk_cred, get_params);
1080 #endif
1082 #ifdef ENABLE_ANON
1083 gnutls_anon_allocate_server_credentials (&dh_cred);
1084 gnutls_anon_set_server_params_function (dh_cred, get_params);
1086 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1087 #endif
1089 #ifdef ENABLE_SESSION_TICKET
1090 if (noticket == 0)
1091 gnutls_session_ticket_key_generate (&session_ticket_key);
1092 #endif
1094 if (listen_socket (name, port) < 0)
1095 exit (1);
1097 for (;;)
1099 listener_item *j;
1100 fd_set rd, wr;
1101 int val;
1103 FD_ZERO (&rd);
1104 FD_ZERO (&wr);
1105 n = 0;
1107 /* flag which connections we are reading or writing to within the fd sets */
1108 lloopstart (listener_list, j)
1111 #ifndef _WIN32
1112 val = fcntl (j->fd, F_GETFL, 0);
1113 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1115 perror ("fcntl()");
1116 exit (1);
1118 #endif
1120 if (j->listen_socket)
1122 FD_SET (j->fd, &rd);
1123 n = MAX (n, j->fd);
1125 if (j->http_state == HTTP_STATE_REQUEST)
1127 FD_SET (j->fd, &rd);
1128 n = MAX (n, j->fd);
1130 if (j->http_state == HTTP_STATE_RESPONSE)
1132 FD_SET (j->fd, &wr);
1133 n = MAX (n, j->fd);
1136 lloopend (listener_list, j);
1138 /* core operation */
1139 n = select (n + 1, &rd, &wr, NULL, NULL);
1140 if (n == -1 && errno == EINTR)
1141 continue;
1142 if (n < 0)
1144 perror ("select()");
1145 exit (1);
1148 /* read or write to each connection as indicated by select()'s return argument */
1149 lloopstart (listener_list, j)
1152 /* a new connection has arrived */
1153 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
1155 gnutls_session_t tls_session;
1157 tls_session = initialize_session ();
1159 calen = sizeof (client_address);
1160 memset (&client_address, 0, calen);
1161 accept_fd = accept (j->fd, (struct sockaddr *) &client_address,
1162 &calen);
1164 if (accept_fd < 0)
1166 perror ("accept()");
1168 else
1170 time_t tt;
1171 char *ctt;
1173 /* new list entry for the connection */
1174 lappend (listener_list);
1175 j = listener_list.tail;
1176 j->http_request = (char *) strdup ("");
1177 j->http_state = HTTP_STATE_REQUEST;
1178 j->fd = accept_fd;
1180 j->tls_session = tls_session;
1181 gnutls_transport_set_ptr (tls_session,
1182 (gnutls_transport_ptr_t)
1183 gl_fd_to_handle (accept_fd));
1184 j->handshake_ok = 0;
1186 if (verbose == 0)
1188 tt = time (0);
1189 ctt = ctime (&tt);
1190 ctt[strlen (ctt) - 1] = 0;
1192 printf ("\n* Accepted connection from %s on %s\n",
1193 human_addr ((struct sockaddr *)
1194 &client_address, calen, topbuf,
1195 sizeof (topbuf)), ctt);
1200 if (FD_ISSET (j->fd, &rd) && !j->listen_socket)
1202 /* read partial GET request */
1203 char buf[1024];
1204 int r, ret;
1206 if (j->handshake_ok == 0)
1208 r = gnutls_handshake (j->tls_session);
1209 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1211 check_alert (j->tls_session, r);
1212 /* nothing */
1214 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1216 check_alert (j->tls_session, r);
1217 fprintf (stderr, "Error in handshake\n");
1218 GERR (r);
1222 ret =
1223 gnutls_alert_send_appropriate (j->tls_session, r);
1225 while (ret == GNUTLS_E_AGAIN);
1226 j->http_state = HTTP_STATE_CLOSING;
1228 else if (r == 0)
1230 if (gnutls_session_is_resumed (j->tls_session) != 0
1231 && verbose == 0)
1232 printf ("*** This is a resumed session\n");
1234 if (verbose == 0)
1236 printf ("\n* Successful handshake from %s\n",
1237 human_addr ((struct sockaddr *)
1238 &client_address, calen, topbuf,
1239 sizeof (topbuf)));
1240 print_info (j->tls_session, NULL, 1);
1242 j->handshake_ok = 1;
1246 if (j->handshake_ok == 1)
1248 r = gnutls_record_recv (j->tls_session, buf,
1249 MIN (1024, SMALL_READ_TEST));
1250 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1252 /* do nothing */
1254 else if (r <= 0)
1256 if (r == GNUTLS_E_REHANDSHAKE)
1258 fprintf(stderr, "*** Received hello message\n");
1261 r = gnutls_handshake (j->tls_session);
1263 while (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN);
1265 else
1267 j->http_state = HTTP_STATE_CLOSING;
1268 if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1270 check_alert (j->tls_session, r);
1271 fprintf (stderr, "Error while receiving data\n");
1272 GERR (r);
1276 else
1278 j->http_request =
1279 realloc (j->http_request, j->request_length + r + 1);
1280 if (j->http_request != NULL)
1282 memcpy (j->http_request + j->request_length, buf, r);
1283 j->request_length += r;
1284 j->http_request[j->request_length] = '\0';
1286 else
1287 j->http_state = HTTP_STATE_CLOSING;
1290 /* check if we have a full HTTP header */
1292 j->http_response = NULL;
1293 if (j->http_request != NULL)
1295 if ((http == 0 && strchr (j->http_request, '\n'))
1296 || strstr (j->http_request, "\r\n\r\n")
1297 || strstr (j->http_request, "\n\n"))
1299 get_response (j->tls_session, j->http_request,
1300 &j->http_response, &j->response_length);
1301 j->http_state = HTTP_STATE_RESPONSE;
1302 j->response_written = 0;
1307 if (FD_ISSET (j->fd, &wr))
1309 /* write partial response request */
1310 int r;
1312 if (j->handshake_ok == 0)
1314 r = gnutls_handshake (j->tls_session);
1315 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1317 check_alert (j->tls_session, r);
1318 /* nothing */
1320 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1322 int ret;
1324 j->http_state = HTTP_STATE_CLOSING;
1325 check_alert (j->tls_session, r);
1326 fprintf (stderr, "Error in handshake\n");
1327 GERR (r);
1331 ret =
1332 gnutls_alert_send_appropriate (j->tls_session, r);
1334 while (ret == GNUTLS_E_AGAIN);
1336 else if (r == 0)
1338 if (gnutls_session_is_resumed (j->tls_session) != 0
1339 && verbose == 0)
1340 printf ("*** This is a resumed session\n");
1341 if (verbose == 0)
1343 printf ("- connection from %s\n",
1344 human_addr ((struct sockaddr *)
1345 &client_address, calen, topbuf,
1346 sizeof (topbuf)));
1348 print_info (j->tls_session, NULL, 1);
1350 j->handshake_ok = 1;
1354 if (j->handshake_ok == 1 && j->http_response != NULL)
1356 /* FIXME if j->http_response == NULL? */
1357 r = gnutls_record_send (j->tls_session,
1358 j->http_response +
1359 j->response_written,
1360 MIN (j->response_length -
1361 j->response_written,
1362 SMALL_READ_TEST));
1363 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1365 /* do nothing */
1367 else if (r <= 0)
1369 if (http != 0)
1370 j->http_state = HTTP_STATE_CLOSING;
1371 else
1373 j->http_state = HTTP_STATE_REQUEST;
1374 free (j->http_response);
1375 j->response_length = 0;
1376 j->request_length = 0;
1377 j->http_request[0] = 0;
1380 if (r < 0)
1382 fprintf (stderr, "Error while sending data\n");
1383 GERR (r);
1385 check_alert (j->tls_session, r);
1387 else
1389 j->response_written += r;
1390 /* check if we have written a complete response */
1391 if (j->response_written == j->response_length)
1393 if (http != 0)
1394 j->http_state = HTTP_STATE_CLOSING;
1395 else
1397 j->http_state = HTTP_STATE_REQUEST;
1398 free (j->http_response);
1399 j->response_length = 0;
1400 j->request_length = 0;
1401 j->http_request[0] = 0;
1406 else
1408 j->request_length = 0;
1409 j->http_request[0] = 0;
1410 j->http_state = HTTP_STATE_REQUEST;
1414 lloopend (listener_list, j);
1416 /* loop through all connections, closing those that are in error */
1417 lloopstart (listener_list, j)
1419 if (j->http_state == HTTP_STATE_CLOSING)
1421 ldeleteinc (listener_list, j);
1424 lloopend (listener_list, j);
1428 gnutls_certificate_free_credentials (cert_cred);
1430 #ifdef ENABLE_SRP
1431 if (srp_cred)
1432 gnutls_srp_free_server_credentials (srp_cred);
1433 #endif
1435 #ifdef ENABLE_PSK
1436 if (psk_cred)
1437 gnutls_psk_free_server_credentials (psk_cred);
1438 #endif
1440 #ifdef ENABLE_ANON
1441 gnutls_anon_free_server_credentials (dh_cred);
1442 #endif
1444 #ifdef ENABLE_SESSION_TICKET
1445 if (noticket == 0)
1446 gnutls_free (session_ticket_key.data);
1447 #endif
1449 if (nodb == 0)
1450 wrap_db_deinit ();
1451 gnutls_global_deinit ();
1453 return 0;
1457 void
1458 gaa_parser (int argc, char **argv)
1460 if (gaa (argc, argv, &info) != -1)
1462 fprintf (stderr,
1463 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1464 exit (1);
1467 disable_client_cert = info.disable_client_cert;
1468 require_cert = info.require_cert;
1469 debug = info.debug;
1470 verbose = info.quiet;
1471 nodb = info.nodb;
1472 noticket = info.noticket;
1474 if (info.http == 0)
1475 http = 0;
1476 else
1477 http = 1;
1479 if (info.fmtder == 0)
1480 x509ctype = GNUTLS_X509_FMT_PEM;
1481 else
1482 x509ctype = GNUTLS_X509_FMT_DER;
1484 if (info.generate == 0)
1485 generate = 0;
1486 else
1487 generate = 1;
1489 dh_params_file = info.dh_params_file;
1491 port = info.port;
1493 x509_certfile = info.x509_certfile;
1494 x509_keyfile = info.x509_keyfile;
1495 x509_dsacertfile = info.x509_dsacertfile;
1496 x509_dsakeyfile = info.x509_dsakeyfile;
1497 x509_cafile = info.x509_cafile;
1498 x509_crlfile = info.x509_crlfile;
1499 pgp_certfile = info.pgp_certfile;
1500 pgp_keyfile = info.pgp_keyfile;
1501 srp_passwd = info.srp_passwd;
1502 srp_passwd_conf = info.srp_passwd_conf;
1504 psk_passwd = info.psk_passwd;
1506 pgp_keyring = info.pgp_keyring;
1508 parse_protocols (info.proto, info.nproto, protocol_priority);
1509 parse_ciphers (info.ciphers, info.nciphers, cipher_priority);
1510 parse_macs (info.macs, info.nmacs, mac_priority);
1511 parse_ctypes (info.ctype, info.nctype, cert_type_priority);
1512 parse_kx (info.kx, info.nkx, kx_priority);
1513 parse_comp (info.comp, info.ncomp, comp_priority);
1516 extern void serv_version (void);
1518 void
1519 serv_version (void)
1521 const char *p = PACKAGE_NAME;
1522 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
1523 p = PACKAGE_STRING;
1524 version_etc (stdout, program_name, p, gnutls_check_version (NULL),
1525 "Nikos Mavrogiannopoulos", (char *) NULL);
1528 /* session resuming support */
1530 #define SESSION_ID_SIZE 32
1531 #define SESSION_DATA_SIZE 1024
1533 typedef struct
1535 char session_id[SESSION_ID_SIZE];
1536 unsigned int session_id_size;
1538 char session_data[SESSION_DATA_SIZE];
1539 unsigned int session_data_size;
1540 } CACHE;
1542 static CACHE *cache_db;
1543 int cache_db_ptr = 0;
1545 static void
1546 wrap_db_init (void)
1548 /* allocate cache_db */
1549 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1552 static void
1553 wrap_db_deinit (void)
1557 static int
1558 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1561 if (cache_db == NULL)
1562 return -1;
1564 if (key.size > SESSION_ID_SIZE)
1565 return -1;
1566 if (data.size > SESSION_DATA_SIZE)
1567 return -1;
1569 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1570 cache_db[cache_db_ptr].session_id_size = key.size;
1572 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1573 cache_db[cache_db_ptr].session_data_size = data.size;
1575 cache_db_ptr++;
1576 cache_db_ptr %= ssl_session_cache;
1578 return 0;
1581 static gnutls_datum_t
1582 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1584 gnutls_datum_t res = { NULL, 0 };
1585 int i;
1587 if (cache_db == NULL)
1588 return res;
1590 for (i = 0; i < ssl_session_cache; i++)
1592 if (key.size == cache_db[i].session_id_size &&
1593 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1595 res.size = cache_db[i].session_data_size;
1597 res.data = gnutls_malloc (res.size);
1598 if (res.data == NULL)
1599 return res;
1601 memcpy (res.data, cache_db[i].session_data, res.size);
1603 return res;
1606 return res;
1609 static int
1610 wrap_db_delete (void *dbf, gnutls_datum_t key)
1612 int i;
1614 if (cache_db == NULL)
1615 return -1;
1617 for (i = 0; i < ssl_session_cache; i++)
1619 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1620 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1623 cache_db[i].session_id_size = 0;
1624 cache_db[i].session_data_size = 0;
1626 return 0;
1630 return -1;