2 * Copyright (C) 2004, 2006, 2007 Free Software Foundation
3 * Copyright (C) 2001,2002 Paul Sheer
4 * Portions Copyright (C) 2002,2003 Nikos Mavroyanopoulos
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 2 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, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 /* This server is heavily modified for GNUTLS by Nikos Mavroyanopoulos
24 * (which means it is quite unreadable)
32 #include <sys/types.h>
34 #include <gnutls/gnutls.h>
35 #include <gnutls/extra.h>
40 #if defined _WIN32 || defined __WIN32__
41 #define select _win_select
45 #include "read-file.h"
47 #include "getaddrinfo.h"
49 /* konqueror cannot handle sending the page in multiple
53 static int generate = 0;
62 int disable_client_cert;
66 char *srp_passwd_conf;
73 char *x509_dsakeyfile;
74 char *x509_dsacertfile;
77 char *x509_crlfile = NULL;
81 /* This is a sample TCP echo server.
82 * This will behave as an http server if any argument in the
83 * command line is present
86 #define SMALL_READ_TEST (2147483647)
88 #define SA struct sockaddr
89 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
90 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
94 #define max(x,y) ((x) > (y) ? (x) : (y))
96 #define min(x,y) ((x) < (y) ? (x) : (y))
99 #define HTTP_END "</BODY></HTML>\n\n"
101 #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"
102 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
104 #define HTTP_BEGIN HTTP_OK \
107 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
108 "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;
120 const int ssl_session_cache = 128;
122 static void wrap_db_init (void);
123 static void wrap_db_deinit (void);
124 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
125 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
126 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
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;
137 int fd; gnutls_session_t tls_session; int handshake_ok;);
140 safe_strerror (int value)
142 const char *ret = gnutls_strerror (value);
149 listener_free (listener_item * j)
153 free (j->http_request);
154 if (j->http_response)
155 free (j->http_response);
158 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
161 gnutls_deinit (j->tls_session);
166 /* we use primes up to 1024 in this server.
167 * otherwise we should add them here.
170 gnutls_dh_params_t dh_params = NULL;
171 gnutls_rsa_params_t rsa_params = NULL;
174 generate_dh_primes (void)
176 int prime_bits = 768;
178 if (gnutls_dh_params_init (&dh_params) < 0)
180 fprintf (stderr, "Error in dh parameter initialization\n");
184 /* Generate Diffie Hellman parameters - for use with DHE
185 * kx algorithms. These should be discarded and regenerated
186 * once a week or once a month. Depends on the
187 * security requirements.
190 ("Generating Diffie Hellman parameters [%d]. Please wait...\n",
194 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
196 fprintf (stderr, "Error in prime generation\n");
204 read_dh_params (void)
208 gnutls_datum_t params;
211 if (gnutls_dh_params_init (&dh_params) < 0)
213 fprintf (stderr, "Error in dh parameter initialization\n");
217 /* read the params file
219 fd = fopen (dh_params_file, "r");
222 fprintf (stderr, "Could not open %s\n", dh_params_file);
226 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
230 params.data = (unsigned char *) tmpdata;
234 gnutls_dh_params_import_pkcs3 (dh_params, ¶ms, GNUTLS_X509_FMT_PEM);
238 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
242 printf ("Read Diffie Hellman parameters.\n");
247 static char pkcs3[] =
248 "-----BEGIN DH PARAMETERS-----\n"
249 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
250 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
251 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
252 "-----END DH PARAMETERS-----\n";
255 static_dh_params (void)
257 gnutls_datum_t params = { pkcs3, sizeof (pkcs3) };
260 if (gnutls_dh_params_init (&dh_params) < 0)
262 fprintf (stderr, "Error in dh parameter initialization\n");
266 ret = gnutls_dh_params_import_pkcs3 (dh_params, ¶ms, GNUTLS_X509_FMT_PEM);
270 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
274 printf ("Set static Diffie Hellman parameters, consider --dhparams.\n");
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)
288 st->params.rsa_export = rsa_params;
290 else if (type == GNUTLS_PARAMS_DH)
292 if (dh_params == NULL)
294 st->params.dh = dh_params;
306 generate_rsa_params (void)
308 if (gnutls_rsa_params_init (&rsa_params) < 0)
310 fprintf (stderr, "Error in rsa parameter initialization\n");
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");
322 if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
324 fprintf (stderr, "Error in rsa parameter generation\n");
331 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
333 static int protocol_priority[PRI_MAX];
334 static int kx_priority[PRI_MAX];
335 static int cipher_priority[PRI_MAX];
336 static int comp_priority[PRI_MAX];
337 static int mac_priority[PRI_MAX];
338 static int cert_type_priority[PRI_MAX];
341 static int authz_server_formats[PRI_MAX] = {
344 static int authz_client_formats[PRI_MAX] = {
345 GNUTLS_AUTHZ_X509_ATTR_CERT,
346 GNUTLS_AUTHZ_SAML_ASSERTION,
347 GNUTLS_AUTHZ_X509_ATTR_CERT_URL,
348 GNUTLS_AUTHZ_SAML_ASSERTION_URL,
353 authz_send_callback (gnutls_session_t session,
354 const int *client_formats,
355 const int *server_formats)
360 printf ("- Client authorization formats: ");
361 for (i = 0; client_formats[i]; i++)
362 printf ("%d ", client_formats[i]);
365 for (i = 0; server_formats[i]; i++)
367 if (server_formats[i] == GNUTLS_AUTHZ_X509_ATTR_CERT
368 && info.authz_x509_attr_cert)
371 const char *x509ac = read_binary_file (info.authz_x509_attr_cert,
374 error (EXIT_FAILURE, errno, "%s", info.authz_x509_attr_cert);
376 printf (" Sending X.509 Attribute Certificate\n");
378 ret = gnutls_authz_send_x509_attr_cert (session,
384 if (server_formats[i] == GNUTLS_AUTHZ_SAML_ASSERTION
385 && info.authz_saml_assertion)
388 const char *samlass = read_binary_file (info.authz_saml_assertion,
391 error (EXIT_FAILURE, errno, "%s", info.authz_saml_assertion);
393 printf (" Sending SAML assertion\n");
395 ret = gnutls_authz_send_saml_assertion (session,
396 samlass, samlass_len);
406 authz_recv_callback (gnutls_session_t session,
407 const int *authz_formats,
408 gnutls_datum_t *infos,
409 const int *hashtypes,
410 gnutls_datum_t *hash)
414 for (i = 0; authz_formats[i]; i++)
416 printf ("- Received authorization data, format %02x of %d bytes\n",
417 authz_formats[i], infos[i].size);
420 for (j = 0; j < infos[i].size; j++)
421 printf ("%02x", infos[i].data[j]);
424 if (hash[i].size > 0)
427 for (j = 0; j < hash[i].size; j++)
428 printf ("%02x", hash[i].data[j]);
429 printf (" type %02x\n", hashtypes[i]);
438 initialize_session (void)
440 gnutls_session_t session;
442 gnutls_init (&session, GNUTLS_SERVER);
444 /* allow the use of private ciphersuites.
446 gnutls_handshake_set_private_extensions (session, 1);
450 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
451 gnutls_db_set_remove_function (session, wrap_db_delete);
452 gnutls_db_set_store_function (session, wrap_db_store);
453 gnutls_db_set_ptr (session, NULL);
456 gnutls_set_default_priority (session);
458 if (cipher_priority[0])
459 gnutls_cipher_set_priority (session, cipher_priority);
460 if (comp_priority[0])
461 gnutls_compression_set_priority (session, comp_priority);
463 gnutls_kx_set_priority (session, kx_priority);
464 if (protocol_priority[0])
465 gnutls_protocol_set_priority (session, protocol_priority);
467 gnutls_mac_set_priority (session, mac_priority);
468 if (cert_type_priority[0])
469 gnutls_certificate_type_set_priority (session, cert_type_priority);
471 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
473 if (srp_cred != NULL)
474 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
476 if (psk_cred != NULL)
477 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
479 if (cert_cred != NULL)
480 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
482 if (disable_client_cert)
483 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
486 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
488 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
492 gnutls_authz_enable (session, authz_client_formats, authz_server_formats,
493 authz_recv_callback, authz_send_callback);
499 #include <gnutls/x509.h>
501 static const char DEFAULT_DATA[] =
502 "This is the default message reported by the GnuTLS implementation. "
503 "For more information please visit "
504 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
506 /* Creates html with the current session information.
508 #define tmp2 &http_buffer[strlen(http_buffer)]
510 peer_print_info (gnutls_session_t session, int *ret_length, const char *header)
513 unsigned char sesid[32];
514 size_t i, sesid_size;
516 gnutls_kx_algorithm_t kx_alg;
517 size_t len = 5 * 1024 + strlen (header);
518 char *crtinfo = NULL;
523 http_buffer = malloc (len);
524 if (http_buffer == NULL)
527 strcpy (http_buffer, HTTP_BEGIN);
528 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
529 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
532 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
537 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
539 const gnutls_datum_t *cert_list;
540 unsigned int cert_list_size = 0;
543 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
545 for (i = 0; i < cert_list_size; i++)
547 gnutls_x509_crt_t cert;
550 if (gnutls_x509_crt_init (&cert) == 0 &&
551 gnutls_x509_crt_import (cert, &cert_list[i],
552 GNUTLS_X509_FMT_DER) == 0 &&
553 gnutls_x509_crt_print (cert, GNUTLS_X509_CRT_FULL, &info) == 0)
555 const char *post = "</PRE><P><PRE>";
557 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
561 memcpy (crtinfo + ncrtinfo, info.data, info.size);
562 ncrtinfo += info.size;
563 memcpy (crtinfo + ncrtinfo, post, strlen (post));
564 ncrtinfo += strlen (post);
565 crtinfo[ncrtinfo] = '\0';
566 gnutls_free (info.data);
571 http_buffer = malloc (len);
572 if (http_buffer == NULL)
575 strcpy (http_buffer, HTTP_BEGIN);
577 /* print session_id */
578 gnutls_session_get_id (session, sesid, &sesid_size);
579 sprintf (tmp2, "\n<p>Session ID: <i>");
580 for (i = 0; i < sesid_size; i++)
581 sprintf (tmp2, "%.2X", sesid[i]);
582 sprintf (tmp2, "</i></p>\n");
584 "<h5>If your browser supports session resuming, then you should see the "
585 "same session ID, when you press the <b>reload</b> button.</h5>\n");
587 /* Here unlike print_info() we use the kx algorithm to distinguish
588 * the functions to call.
592 size_t dns_size = sizeof (dns);
595 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
597 sprintf (tmp2, "\n<p>Server Name: %s</p>\n", dns);
602 kx_alg = gnutls_kx_get (session);
604 /* print srp specific data */
606 if (kx_alg == GNUTLS_KX_SRP)
608 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
609 gnutls_srp_server_get_username (session));
614 if (kx_alg == GNUTLS_KX_PSK)
616 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
617 gnutls_psk_server_get_username (session));
622 if (kx_alg == GNUTLS_KX_ANON_DH)
625 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
626 gnutls_dh_get_prime_bits (session));
630 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
633 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
634 gnutls_dh_get_prime_bits (session));
637 /* print session information */
638 strcat (http_buffer, "<P>\n");
640 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
644 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
647 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
650 gnutls_certificate_type_get_name (gnutls_certificate_type_get
654 sprintf (tmp2, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
657 tmp = gnutls_kx_get_name (kx_alg);
660 sprintf (tmp2, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
662 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
665 sprintf (tmp2, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
667 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
670 sprintf (tmp2, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
672 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
675 sprintf (tmp2, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
677 tmp = gnutls_cipher_suite_get_name (kx_alg,
678 gnutls_cipher_get (session),
679 gnutls_mac_get (session));
682 sprintf (tmp2, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
687 strcat (http_buffer, "<hr><PRE>");
688 strcat (http_buffer, crtinfo);
689 strcat (http_buffer, "\n</PRE>\n");
692 strcat (http_buffer, "<hr><P>Your HTTP header was:<PRE>");
693 strcat (http_buffer, header);
694 strcat (http_buffer, "</PRE></P>");
696 strcat (http_buffer, "\n" HTTP_END);
698 *ret_length = strlen (http_buffer);
704 listen_socket (const char *name, int listen_port)
706 struct addrinfo hints, *res, *ptr;
711 snprintf (portname, sizeof (portname), "%d", listen_port);
712 memset (&hints, 0, sizeof (hints));
713 hints.ai_socktype = SOCK_STREAM;
714 hints.ai_flags = AI_PASSIVE;
716 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
718 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
723 for (ptr = res; (ptr != NULL) && (s == -1); ptr = ptr->ai_next)
725 if ((s = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) < 0)
727 perror ("socket() failed");
733 (s, SOL_SOCKET, SO_REUSEADDR, (const void *) &yes, sizeof (yes)) < 0)
735 perror ("setsockopt() failed");
742 if (bind (s, res->ai_addr, res->ai_addrlen) < 0)
744 perror ("bind() failed");
748 if (listen (s, 10) < 0)
750 perror ("listen() failed");
761 printf ("%s ready. Listening to port '%s'.\n\n", name, portname);
766 get_response (gnutls_session_t session, char *request,
767 char **response, int *response_length)
773 if (strncmp (request, "GET ", 4))
776 if (!(h = strchr (request, '\n')))
780 while (*h == '\r' || *h == '\n')
783 if (!(p = strchr (request + 4, ' ')))
787 /* *response = peer_print_info(session, request+4, h, response_length); */
790 *response = peer_print_info (session, response_length, h);
794 *response = strdup (request);
795 *response_length = ((*response) ? strlen (*response) : 0);
801 *response = strdup (HTTP_UNIMPLEMENTED);
802 *response_length = ((*response) ? strlen (*response) : 0);
808 fprintf (stderr, "Exiting via signal %d\n", sig);
814 check_alert (gnutls_session_t session, int ret)
816 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
817 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
819 int last_alert = gnutls_alert_get (session);
820 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
821 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
823 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
825 printf ("* Received alert '%d': %s.\n", last_alert,
826 gnutls_alert_get_name (last_alert));
831 tls_log_func (int level, const char *str)
833 fprintf (stderr, "|<%d>| %s", level, str);
836 static void gaa_parser (int argc, char **argv);
838 static int get_port (const struct sockaddr_storage *addr)
840 switch (addr->ss_family)
843 return ntohs (((const struct sockaddr_in6 *)addr)->sin6_port);
845 return ntohs (((const struct sockaddr_in *)addr)->sin_port);
850 static const char *addr_ntop (const struct sockaddr *sa, socklen_t salen,
851 char *buf, size_t buflen)
853 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0)
861 main (int argc, char **argv)
867 struct sockaddr_storage client_address;
871 signal (SIGPIPE, SIG_IGN);
872 signal (SIGHUP, SIG_IGN);
873 signal (SIGTERM, terminate);
874 if (signal (SIGINT, terminate) == SIG_IGN)
875 signal (SIGINT, SIG_IGN); /* e.g. background process */
880 gaa_parser (argc, argv);
887 strcpy (name, "HTTP Server");
891 strcpy (name, "Echo Server");
894 if ((ret = gnutls_global_init ()) < 0)
896 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
899 gnutls_global_set_log_function (tls_log_func);
900 gnutls_global_set_log_level (debug);
902 if ((ret = gnutls_global_init_extra ()) < 0)
904 fprintf (stderr, "global_init_extra: %s\n", gnutls_strerror (ret));
908 /* Note that servers must generate parameters for
909 * Diffie Hellman. See gnutls_dh_params_generate(), and
910 * gnutls_dh_params_set().
914 generate_rsa_params ();
915 generate_dh_primes ();
917 else if (dh_params_file)
926 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
928 fprintf (stderr, "memory error\n");
932 if (x509_cafile != NULL)
934 if ((ret = gnutls_certificate_set_x509_trust_file
935 (cert_cred, x509_cafile, x509ctype)) < 0)
937 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
943 printf ("Processed %d CA certificate(s).\n", ret);
947 if (x509_crlfile != NULL)
949 if ((ret = gnutls_certificate_set_x509_crl_file
950 (cert_cred, x509_crlfile, x509ctype)) < 0)
952 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
958 printf ("Processed %d CRL(s).\n", ret);
963 #ifdef ENABLE_OPENPGP
964 if (pgp_keyring != NULL)
967 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring);
970 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
975 if (pgp_trustdb != NULL)
977 ret = gnutls_certificate_set_openpgp_trustdb (cert_cred, pgp_trustdb);
980 fprintf (stderr, "Error setting the OpenPGP trustdb file\n");
985 if (pgp_certfile != NULL)
986 if ((ret = gnutls_certificate_set_openpgp_key_file
987 (cert_cred, pgp_certfile, pgp_keyfile)) < 0)
990 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
991 ret, pgp_certfile, pgp_keyfile);
996 if (x509_certfile != NULL)
997 if ((ret = gnutls_certificate_set_x509_key_file
998 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
1001 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1006 if (x509_dsacertfile != NULL)
1007 if ((ret = gnutls_certificate_set_x509_key_file
1008 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1010 fprintf (stderr, "Error reading '%s' or '%s'\n",
1011 x509_dsacertfile, x509_dsakeyfile);
1016 gnutls_certificate_set_params_function (cert_cred, get_params);
1017 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1018 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1021 /* this is a password file (created with the included srpcrypt utility)
1022 * Read README.crypt prior to using SRP.
1025 if (srp_passwd != NULL)
1027 gnutls_srp_allocate_server_credentials (&srp_cred);
1030 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1031 srp_passwd_conf)) < 0)
1033 /* only exit is this function is not disabled
1035 fprintf (stderr, "Error while setting SRP parameters\n");
1041 /* this is a password file
1044 if (psk_passwd != NULL)
1046 gnutls_psk_allocate_server_credentials (&psk_cred);
1049 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1051 /* only exit is this function is not disabled
1053 fprintf (stderr, "Error while setting PSK parameters\n");
1057 gnutls_psk_set_server_params_function (psk_cred, get_params);
1062 gnutls_anon_allocate_server_credentials (&dh_cred);
1063 gnutls_anon_set_server_params_function (dh_cred, get_params);
1065 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1068 h = listen_socket (name, port);
1082 /* check for new incoming connections */
1086 /* flag which connections we are reading or writing to within the fd sets */
1087 lloopstart (listener_list, j)
1091 val = fcntl (j->fd, F_GETFL, 0);
1092 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1099 if (j->http_state == HTTP_STATE_REQUEST)
1101 FD_SET (j->fd, &rd);
1104 if (j->http_state == HTTP_STATE_RESPONSE)
1106 FD_SET (j->fd, &wr);
1110 lloopend (listener_list, j);
1112 /* core operation */
1113 n = select (n + 1, &rd, &wr, NULL, NULL);
1114 if (n == -1 && errno == EINTR)
1118 perror ("select()");
1122 /* a new connection has arrived */
1123 if (FD_ISSET (h, &rd))
1125 gnutls_session_t tls_session;
1127 tls_session = initialize_session ();
1129 calen = sizeof (client_address);
1130 memset (&client_address, 0, calen);
1131 accept_fd = accept (h, (struct sockaddr *) &client_address, &calen);
1135 perror ("accept()");
1142 /* new list entry for the connection */
1143 lappend (listener_list);
1144 j = listener_list.tail;
1145 j->http_request = (char *) strdup ("");
1146 j->http_state = HTTP_STATE_REQUEST;
1149 j->tls_session = tls_session;
1150 gnutls_transport_set_ptr (tls_session,
1151 (gnutls_transport_ptr_t) accept_fd);
1152 j->handshake_ok = 0;
1158 ctt[strlen (ctt) - 1] = 0;
1161 printf("\n* connection from %s, port %d\n",
1162 inet_ntop(AF_INET, &client_address.sin_addr, topbuf,
1163 sizeof(topbuf)), ntohs(client_address.sin_port));
1170 /* read or write to each connection as indicated by select()'s return argument */
1171 lloopstart (listener_list, j)
1173 if (FD_ISSET (j->fd, &rd))
1175 /* read partial GET request */
1179 if (j->handshake_ok == 0)
1181 r = gnutls_handshake (j->tls_session);
1182 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1184 check_alert (j->tls_session, r);
1187 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1189 check_alert (j->tls_session, r);
1190 fprintf (stderr, "Error in handshake\n");
1196 gnutls_alert_send_appropriate (j->tls_session, r);
1198 while (ret == GNUTLS_E_AGAIN);
1199 j->http_state = HTTP_STATE_CLOSING;
1203 if (gnutls_session_is_resumed (j->tls_session) != 0
1205 printf ("*** This is a resumed session\n");
1209 printf ("\n* connection from %s, port %d\n",
1210 addr_ntop ((struct sockaddr *)&client_address, calen,
1211 topbuf, sizeof (topbuf)),
1212 get_port (&client_address));
1213 print_info (j->tls_session, NULL);
1215 j->handshake_ok = 1;
1219 if (j->handshake_ok == 1)
1221 r = gnutls_record_recv (j->tls_session, buf,
1222 min (1024, SMALL_READ_TEST));
1223 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1229 j->http_state = HTTP_STATE_CLOSING;
1230 if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1232 check_alert (j->tls_session, r);
1233 fprintf (stderr, "Error while receiving data\n");
1241 realloc (j->http_request, j->request_length + r + 1);
1242 if (j->http_request != NULL)
1244 memcpy (j->http_request + j->request_length, buf, r);
1245 j->request_length += r;
1246 j->http_request[j->request_length] = '\0';
1249 j->http_state = HTTP_STATE_CLOSING;
1252 /* check if we have a full HTTP header */
1254 j->http_response = NULL;
1255 if (j->http_request != NULL)
1257 if ((http == 0 && strchr (j->http_request, '\n'))
1258 || strstr (j->http_request, "\r\n\r\n")
1259 || strstr (j->http_request, "\n\n"))
1261 get_response (j->tls_session, j->http_request,
1262 &j->http_response, &j->response_length);
1263 j->http_state = HTTP_STATE_RESPONSE;
1264 j->response_written = 0;
1269 if (FD_ISSET (j->fd, &wr))
1271 /* write partial response request */
1274 if (j->handshake_ok == 0)
1276 r = gnutls_handshake (j->tls_session);
1277 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1279 check_alert (j->tls_session, r);
1282 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1286 j->http_state = HTTP_STATE_CLOSING;
1287 check_alert (j->tls_session, r);
1288 fprintf (stderr, "Error in handshake\n");
1294 gnutls_alert_send_appropriate (j->tls_session, r);
1296 while (ret == GNUTLS_E_AGAIN);
1300 if (gnutls_session_is_resumed (j->tls_session) != 0
1302 printf ("*** This is a resumed session\n");
1305 printf ("- connection from %s, port %d\n",
1306 addr_ntop ((struct sockaddr*) &client_address, calen,
1307 topbuf, sizeof (topbuf)),
1308 get_port (&client_address));
1310 print_info (j->tls_session, NULL);
1312 j->handshake_ok = 1;
1316 if (j->handshake_ok == 1)
1318 /* FIXME if j->http_response == NULL? */
1319 r = gnutls_record_send (j->tls_session,
1321 j->response_written,
1322 min (j->response_length -
1323 j->response_written,
1325 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1332 j->http_state = HTTP_STATE_CLOSING;
1335 j->http_state = HTTP_STATE_REQUEST;
1336 free (j->http_response);
1337 j->response_length = 0;
1338 j->request_length = 0;
1339 j->http_request[0] = 0;
1344 fprintf (stderr, "Error while sending data\n");
1347 check_alert (j->tls_session, r);
1351 j->response_written += r;
1352 /* check if we have written a complete response */
1353 if (j->response_written == j->response_length)
1356 j->http_state = HTTP_STATE_CLOSING;
1359 j->http_state = HTTP_STATE_REQUEST;
1360 free (j->http_response);
1361 j->response_length = 0;
1362 j->request_length = 0;
1363 j->http_request[0] = 0;
1370 lloopend (listener_list, j);
1372 /* loop through all connections, closing those that are in error */
1373 lloopstart (listener_list, j)
1375 if (j->http_state == HTTP_STATE_CLOSING)
1377 ldeleteinc (listener_list, j);
1380 lloopend (listener_list, j);
1384 gnutls_certificate_free_credentials (cert_cred);
1388 gnutls_srp_free_server_credentials (srp_cred);
1393 gnutls_psk_free_server_credentials (psk_cred);
1397 gnutls_anon_free_server_credentials (dh_cred);
1402 gnutls_global_deinit ();
1409 gaa_parser (int argc, char **argv)
1411 if (gaa (argc, argv, &info) != -1)
1414 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1418 disable_client_cert = info.disable_client_cert;
1419 require_cert = info.require_cert;
1421 verbose = info.quiet;
1429 if (info.fmtder == 0)
1430 x509ctype = GNUTLS_X509_FMT_PEM;
1432 x509ctype = GNUTLS_X509_FMT_DER;
1434 if (info.generate == 0)
1439 dh_params_file = info.dh_params_file;
1443 x509_certfile = info.x509_certfile;
1444 x509_keyfile = info.x509_keyfile;
1445 x509_dsacertfile = info.x509_dsacertfile;
1446 x509_dsakeyfile = info.x509_dsakeyfile;
1447 x509_cafile = info.x509_cafile;
1448 x509_crlfile = info.x509_crlfile;
1449 pgp_certfile = info.pgp_certfile;
1450 pgp_keyfile = info.pgp_keyfile;
1451 srp_passwd = info.srp_passwd;
1452 srp_passwd_conf = info.srp_passwd_conf;
1454 psk_passwd = info.psk_passwd;
1456 pgp_keyring = info.pgp_keyring;
1457 pgp_trustdb = info.pgp_trustdb;
1459 parse_protocols (info.proto, info.nproto, protocol_priority);
1460 parse_ciphers (info.ciphers, info.nciphers, cipher_priority);
1461 parse_macs (info.macs, info.nmacs, mac_priority);
1462 parse_ctypes (info.ctype, info.nctype, cert_type_priority);
1463 parse_kx (info.kx, info.nkx, kx_priority);
1464 parse_comp (info.comp, info.ncomp, comp_priority);
1468 size_t authz_idx = 0;
1469 if (info.authz_x509_attr_cert)
1470 authz_server_formats[authz_idx++] = GNUTLS_AUTHZ_X509_ATTR_CERT;
1471 if (info.authz_saml_assertion)
1472 authz_server_formats[authz_idx++] = GNUTLS_AUTHZ_SAML_ASSERTION;
1480 const char *v = gnutls_check_version (NULL);
1482 printf ("gnutls-serv (GnuTLS) %s\n", LIBGNUTLS_VERSION);
1483 if (strcmp (v, LIBGNUTLS_VERSION) != 0)
1484 printf ("libgnutls %s\n", v);
1487 /* session resuming support */
1489 #define SESSION_ID_SIZE 32
1490 #define SESSION_DATA_SIZE 1024
1494 char session_id[SESSION_ID_SIZE];
1495 unsigned int session_id_size;
1497 char session_data[SESSION_DATA_SIZE];
1498 unsigned int session_data_size;
1501 static CACHE *cache_db;
1502 int cache_db_ptr = 0;
1508 /* allocate cache_db */
1509 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1513 wrap_db_deinit (void)
1518 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1521 if (cache_db == NULL)
1524 if (key.size > SESSION_ID_SIZE)
1526 if (data.size > SESSION_DATA_SIZE)
1529 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1530 cache_db[cache_db_ptr].session_id_size = key.size;
1532 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1533 cache_db[cache_db_ptr].session_data_size = data.size;
1536 cache_db_ptr %= ssl_session_cache;
1541 static gnutls_datum_t
1542 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1544 gnutls_datum_t res = { NULL, 0 };
1547 if (cache_db == NULL)
1550 for (i = 0; i < ssl_session_cache; i++)
1552 if (key.size == cache_db[i].session_id_size &&
1553 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1557 res.size = cache_db[i].session_data_size;
1559 res.data = gnutls_malloc (res.size);
1560 if (res.data == NULL)
1563 memcpy (res.data, cache_db[i].session_data, res.size);
1572 wrap_db_delete (void *dbf, gnutls_datum_t key)
1576 if (cache_db == NULL)
1579 for (i = 0; i < ssl_session_cache; i++)
1581 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1582 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1585 cache_db[i].session_id_size = 0;
1586 cache_db[i].session_data_size = 0;
1597 print_serv_license (void)
1599 fputs ("\nCopyright (C) 2001-2003 Paul Sheer, Nikos Mavroyanopoulos\n"
1600 "\nCopyright (C) 2004 Free Software Foundation\n"
1601 "This program is free software; you can redistribute it and/or modify \n"
1602 "it under the terms of the GNU General Public License as published by \n"
1603 "the Free Software Foundation; either version 2 of the License, or \n"
1604 "(at your option) any later version. \n" "\n"
1605 "This program is distributed in the hope that it will be useful, \n"
1606 "but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
1607 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n"
1608 "GNU General Public License for more details. \n" "\n"
1609 "You should have received a copy of the GNU General Public License \n"
1610 "along with this program; if not, write to the Free Software \n"
1611 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",