Update `NEWS'.
[gnutls.git] / src / serv.c
blob100165fcae04ee898e7f9eb90632500638d4598f
1 /*
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)
27 #include "common.h"
28 #include "serv-gaa.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <string.h>
34 #include <gnutls/gnutls.h>
35 #include <gnutls/extra.h>
36 #include <sys/time.h>
37 #include <fcntl.h>
38 #include <list.h>
40 #if defined _WIN32 || defined __WIN32__
41 #define select _win_select
42 #endif
44 #include "error.h"
45 #include "read-file.h"
47 #include "getaddrinfo.h"
49 /* konqueror cannot handle sending the page in multiple
50 * pieces.
52 /* global stuff */
53 static int generate = 0;
54 static int http = 0;
55 static int port = 0;
56 static int x509ctype;
57 static int debug;
59 int verbose;
60 static int nodb;
61 int require_cert;
62 int disable_client_cert;
64 char *psk_passwd;
65 char *srp_passwd;
66 char *srp_passwd_conf;
67 char *pgp_keyring;
68 char *pgp_trustdb;
69 char *pgp_keyfile;
70 char *pgp_certfile;
71 char *x509_keyfile;
72 char *x509_certfile;
73 char *x509_dsakeyfile;
74 char *x509_dsacertfile;
75 char *x509_cafile;
76 char *dh_params_file;
77 char *x509_crlfile = NULL;
79 /* end of globals */
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))
91 #define MAX_BUF 1024
93 #undef max
94 #define max(x,y) ((x) > (y) ? (x) : (y))
95 #undef min
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 \
105 "\n" \
106 "<HTML><BODY>\n" \
107 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
108 "GNUTLS</a></H1></CENTER>\n\n"
110 #define RENEGOTIATE
112 /* These are global */
113 gnutls_srp_server_credentials_t srp_cred = NULL;
114 gnutls_psk_server_credentials_t psk_cred = NULL;
115 gnutls_anon_server_credentials_t dh_cred = NULL;
116 gnutls_certificate_credentials_t cert_cred = NULL;
118 static gaainfo info;
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;
136 int http_state;
137 int fd; gnutls_session_t tls_session; int handshake_ok;);
139 static const char *
140 safe_strerror (int value)
142 const char *ret = gnutls_strerror (value);
143 if (ret == NULL)
144 ret = str_unknown;
145 return ret;
148 static void
149 listener_free (listener_item * j)
152 if (j->http_request)
153 free (j->http_request);
154 if (j->http_response)
155 free (j->http_response);
156 if (j->fd >= 0)
158 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
159 shutdown (j->fd, 2);
160 close (j->fd);
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;
173 static int
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");
181 exit (1);
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.
189 printf
190 ("Generating Diffie Hellman parameters [%d]. Please wait...\n",
191 prime_bits);
192 fflush (stdout);
194 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
196 fprintf (stderr, "Error in prime generation\n");
197 exit (1);
200 return 0;
203 static void
204 read_dh_params (void)
206 char tmpdata[2048];
207 int size;
208 gnutls_datum_t params;
209 FILE *fd;
211 if (gnutls_dh_params_init (&dh_params) < 0)
213 fprintf (stderr, "Error in dh parameter initialization\n");
214 exit (1);
217 /* read the params file
219 fd = fopen (dh_params_file, "r");
220 if (fd == NULL)
222 fprintf (stderr, "Could not open %s\n", dh_params_file);
223 exit (1);
226 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
227 tmpdata[size] = 0;
228 fclose (fd);
230 params.data = (unsigned char *) tmpdata;
231 params.size = size;
233 size =
234 gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
236 if (size < 0)
238 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
239 exit (1);
242 printf ("Read Diffie Hellman parameters.\n");
243 fflush (stdout);
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";
254 static int
255 static_dh_params (void)
257 gnutls_datum_t params = { pkcs3, sizeof (pkcs3) };
258 int ret;
260 if (gnutls_dh_params_init (&dh_params) < 0)
262 fprintf (stderr, "Error in dh parameter initialization\n");
263 exit (1);
266 ret = gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
268 if (ret < 0)
270 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
271 exit (1);
274 printf ("Set static Diffie Hellman parameters, consider --dhparams.\n");
276 return 0;
279 static int
280 get_params (gnutls_session_t session, gnutls_params_type_t type,
281 gnutls_params_st * st)
284 if (type == GNUTLS_PARAMS_RSA_EXPORT)
286 if (rsa_params == NULL)
287 return -1;
288 st->params.rsa_export = rsa_params;
290 else if (type == GNUTLS_PARAMS_DH)
292 if (dh_params == NULL)
293 return -1;
294 st->params.dh = dh_params;
296 else
297 return -1;
299 st->type = type;
300 st->deinit = 0;
302 return 0;
305 static int
306 generate_rsa_params (void)
308 if (gnutls_rsa_params_init (&rsa_params) < 0)
310 fprintf (stderr, "Error in rsa parameter initialization\n");
311 exit (1);
314 /* Generate RSA parameters - for use with RSA-export
315 * cipher suites. These should be discarded and regenerated
316 * once a day, once every 500 transactions etc. Depends on the
317 * security requirements.
319 printf ("Generating temporary RSA parameters. Please wait...\n");
320 fflush (stdout);
322 if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
324 fprintf (stderr, "Error in rsa parameter generation\n");
325 exit (1);
328 return 0;
331 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
333 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];
340 #ifdef ENABLE_AUTHZ
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)
357 size_t i;
358 int ret;
360 printf ("- Client authorization formats: ");
361 for (i = 0; client_formats[i]; i++)
362 printf ("%d ", client_formats[i]);
363 printf ("\n");
365 for (i = 0; server_formats[i]; i++)
367 if (server_formats[i] == GNUTLS_AUTHZ_X509_ATTR_CERT
368 && info.authz_x509_attr_cert)
370 size_t x509ac_len;
371 const char *x509ac = read_binary_file (info.authz_x509_attr_cert,
372 &x509ac_len);
373 if (!x509ac)
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,
379 x509ac, x509ac_len);
380 if (ret < 0)
381 return ret;
384 if (server_formats[i] == GNUTLS_AUTHZ_SAML_ASSERTION
385 && info.authz_saml_assertion)
387 size_t samlass_len;
388 const char *samlass = read_binary_file (info.authz_saml_assertion,
389 &samlass_len);
390 if (!samlass)
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);
397 if (ret < 0)
398 return ret;
402 return 0;
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)
412 size_t i, j;
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);
419 printf (" data: ");
420 for (j = 0; j < infos[i].size; j++)
421 printf ("%02x", infos[i].data[j]);
422 printf ("\n");
424 if (hash[i].size > 0)
426 printf (" hash: ");
427 for (j = 0; j < hash[i].size; j++)
428 printf ("%02x", hash[i].data[j]);
429 printf (" type %02x\n", hashtypes[i]);
433 return 0;
435 #endif
437 #if ENABLE_OPRFI
439 oprfi_callback (gnutls_session_t session,
440 void *userdata,
441 size_t oprfi_len,
442 const unsigned char *in_oprfi,
443 unsigned char *out_oprfi)
445 size_t ourlen = strlen (info.opaque_prf_input);
446 size_t i;
448 printf ("- Received Opaque PRF data of %d bytes\n", oprfi_len);
449 printf (" data: ");
450 for (i = 0; i < oprfi_len; i++)
451 printf ("%02x", in_oprfi[i]);
452 printf ("\n");
454 memset(out_oprfi, 0, oprfi_len);
455 strncpy (out_oprfi, info.opaque_prf_input, oprfi_len);
457 return 0;
459 #endif
461 gnutls_session_t
462 initialize_session (void)
464 gnutls_session_t session;
466 gnutls_init (&session, GNUTLS_SERVER);
468 /* allow the use of private ciphersuites.
470 gnutls_handshake_set_private_extensions (session, 1);
472 if (nodb == 0)
474 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
475 gnutls_db_set_remove_function (session, wrap_db_delete);
476 gnutls_db_set_store_function (session, wrap_db_store);
477 gnutls_db_set_ptr (session, NULL);
480 gnutls_set_default_priority (session);
482 if (cipher_priority[0])
483 gnutls_cipher_set_priority (session, cipher_priority);
484 if (comp_priority[0])
485 gnutls_compression_set_priority (session, comp_priority);
486 if (kx_priority[0])
487 gnutls_kx_set_priority (session, kx_priority);
488 if (protocol_priority[0])
489 gnutls_protocol_set_priority (session, protocol_priority);
490 if (mac_priority[0])
491 gnutls_mac_set_priority (session, mac_priority);
492 if (cert_type_priority[0])
493 gnutls_certificate_type_set_priority (session, cert_type_priority);
495 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
497 if (srp_cred != NULL)
498 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
500 if (psk_cred != NULL)
501 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
503 if (cert_cred != NULL)
504 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
506 if (disable_client_cert)
507 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
508 else {
509 if (require_cert)
510 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
511 else
512 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
515 #ifdef ENABLE_AUTHZ
516 gnutls_authz_enable (session, authz_client_formats, authz_server_formats,
517 authz_recv_callback, authz_send_callback);
518 #endif
520 #ifdef ENABLE_OPRFI
521 if (info.opaque_prf_input)
522 gnutls_oprfi_enable_server (session, oprfi_callback, NULL);
523 #endif
525 return session;
528 #include <gnutls/x509.h>
530 static const char DEFAULT_DATA[] =
531 "This is the default message reported by the GnuTLS implementation. "
532 "For more information please visit "
533 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
535 /* Creates html with the current session information.
537 #define tmp2 &http_buffer[strlen(http_buffer)]
538 char *
539 peer_print_info (gnutls_session_t session, int *ret_length, const char *header)
541 const char *tmp;
542 unsigned char sesid[32];
543 size_t i, sesid_size;
544 char *http_buffer;
545 gnutls_kx_algorithm_t kx_alg;
546 size_t len = 5 * 1024 + strlen (header);
547 char *crtinfo = NULL;
548 size_t ncrtinfo = 0;
550 if (verbose != 0)
552 http_buffer = malloc (len);
553 if (http_buffer == NULL)
554 return NULL;
556 strcpy (http_buffer, HTTP_BEGIN);
557 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
558 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
559 HTTP_END);
560 *ret_length =
561 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
562 return http_buffer;
566 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
568 const gnutls_datum_t *cert_list;
569 unsigned int cert_list_size = 0;
570 size_t i;
572 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
574 for (i = 0; i < cert_list_size; i++)
576 gnutls_x509_crt_t cert;
577 gnutls_datum_t info;
579 if (gnutls_x509_crt_init (&cert) == 0 &&
580 gnutls_x509_crt_import (cert, &cert_list[i],
581 GNUTLS_X509_FMT_DER) == 0 &&
582 gnutls_x509_crt_print (cert, GNUTLS_X509_CRT_FULL, &info) == 0)
584 const char *post = "</PRE><P><PRE>";
586 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
587 strlen (post) + 1);
588 if (crtinfo == NULL)
589 return NULL;
590 memcpy (crtinfo + ncrtinfo, info.data, info.size);
591 ncrtinfo += info.size;
592 memcpy (crtinfo + ncrtinfo, post, strlen (post));
593 ncrtinfo += strlen (post);
594 crtinfo[ncrtinfo] = '\0';
595 gnutls_free (info.data);
600 http_buffer = malloc (len);
601 if (http_buffer == NULL)
602 return NULL;
604 strcpy (http_buffer, HTTP_BEGIN);
606 /* print session_id */
607 gnutls_session_get_id (session, sesid, &sesid_size);
608 sprintf (tmp2, "\n<p>Session ID: <i>");
609 for (i = 0; i < sesid_size; i++)
610 sprintf (tmp2, "%.2X", sesid[i]);
611 sprintf (tmp2, "</i></p>\n");
612 sprintf (tmp2,
613 "<h5>If your browser supports session resuming, then you should see the "
614 "same session ID, when you press the <b>reload</b> button.</h5>\n");
616 /* Here unlike print_info() we use the kx algorithm to distinguish
617 * the functions to call.
620 char dns[256];
621 size_t dns_size = sizeof (dns);
622 unsigned int type;
624 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
626 sprintf (tmp2, "\n<p>Server Name: %s</p>\n", dns);
631 kx_alg = gnutls_kx_get (session);
633 /* print srp specific data */
634 #ifdef ENABLE_SRP
635 if (kx_alg == GNUTLS_KX_SRP)
637 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
638 gnutls_srp_server_get_username (session));
640 #endif
642 #ifdef ENABLE_PSK
643 if (kx_alg == GNUTLS_KX_PSK)
645 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
646 gnutls_psk_server_get_username (session));
648 #endif
650 #ifdef ENABLE_ANON
651 if (kx_alg == GNUTLS_KX_ANON_DH)
653 sprintf (tmp2,
654 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
655 gnutls_dh_get_prime_bits (session));
657 #endif
659 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
661 sprintf (tmp2,
662 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
663 gnutls_dh_get_prime_bits (session));
666 /* print session information */
667 strcat (http_buffer, "<P>\n");
669 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
670 if (tmp == NULL)
671 tmp = str_unknown;
672 sprintf (tmp2,
673 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
674 tmp);
676 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
678 tmp =
679 gnutls_certificate_type_get_name (gnutls_certificate_type_get
680 (session));
681 if (tmp == NULL)
682 tmp = str_unknown;
683 sprintf (tmp2, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
686 tmp = gnutls_kx_get_name (kx_alg);
687 if (tmp == NULL)
688 tmp = str_unknown;
689 sprintf (tmp2, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
691 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
692 if (tmp == NULL)
693 tmp = str_unknown;
694 sprintf (tmp2, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
696 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
697 if (tmp == NULL)
698 tmp = str_unknown;
699 sprintf (tmp2, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
701 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
702 if (tmp == NULL)
703 tmp = str_unknown;
704 sprintf (tmp2, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
706 tmp = gnutls_cipher_suite_get_name (kx_alg,
707 gnutls_cipher_get (session),
708 gnutls_mac_get (session));
709 if (tmp == NULL)
710 tmp = str_unknown;
711 sprintf (tmp2, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
712 tmp);
714 if (crtinfo)
716 strcat (http_buffer, "<hr><PRE>");
717 strcat (http_buffer, crtinfo);
718 strcat (http_buffer, "\n</PRE>\n");
721 strcat (http_buffer, "<hr><P>Your HTTP header was:<PRE>");
722 strcat (http_buffer, header);
723 strcat (http_buffer, "</PRE></P>");
725 strcat (http_buffer, "\n" HTTP_END);
727 *ret_length = strlen (http_buffer);
729 return http_buffer;
732 static int
733 listen_socket (const char *name, int listen_port)
735 struct addrinfo hints, *res, *ptr;
736 char portname[6];
737 int s;
738 int yes;
740 snprintf (portname, sizeof (portname), "%d", listen_port);
741 memset (&hints, 0, sizeof (hints));
742 hints.ai_socktype = SOCK_STREAM;
743 hints.ai_flags = AI_PASSIVE;
745 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
747 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
748 return -1;
750 s = -1;
752 for (ptr = res; (ptr != NULL) && (s == -1); ptr = ptr->ai_next)
754 if ((s = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) < 0)
756 perror ("socket() failed");
757 continue;
760 yes = 1;
761 if (setsockopt
762 (s, SOL_SOCKET, SO_REUSEADDR, (const void *) &yes, sizeof (yes)) < 0)
764 perror ("setsockopt() failed");
765 failed:
766 close (s);
767 s = -1;
768 continue;
771 if (bind (s, res->ai_addr, res->ai_addrlen) < 0)
773 perror ("bind() failed");
774 goto failed;
777 if (listen (s, 10) < 0)
779 perror ("listen() failed");
780 goto failed;
784 freeaddrinfo (res);
785 if (s == -1)
787 return -1;
790 printf ("%s ready. Listening to port '%s'.\n\n", name, portname);
791 return s;
794 static void
795 get_response (gnutls_session_t session, char *request,
796 char **response, int *response_length)
798 char *p, *h;
800 if (http != 0)
802 if (strncmp (request, "GET ", 4))
803 goto unimplemented;
805 if (!(h = strchr (request, '\n')))
806 goto unimplemented;
808 *h++ = '\0';
809 while (*h == '\r' || *h == '\n')
810 h++;
812 if (!(p = strchr (request + 4, ' ')))
813 goto unimplemented;
814 *p = '\0';
816 /* *response = peer_print_info(session, request+4, h, response_length); */
817 if (http != 0)
819 *response = peer_print_info (session, response_length, h);
821 else
823 *response = strdup (request);
824 *response_length = ((*response) ? strlen (*response) : 0);
827 return;
829 unimplemented:
830 *response = strdup (HTTP_UNIMPLEMENTED);
831 *response_length = ((*response) ? strlen (*response) : 0);
834 void
835 terminate (int sig)
837 fprintf (stderr, "Exiting via signal %d\n", sig);
838 exit (1);
842 static void
843 check_alert (gnutls_session_t session, int ret)
845 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
846 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
848 int last_alert = gnutls_alert_get (session);
849 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
850 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
851 printf
852 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
853 else
854 printf ("* Received alert '%d': %s.\n", last_alert,
855 gnutls_alert_get_name (last_alert));
859 static void
860 tls_log_func (int level, const char *str)
862 fprintf (stderr, "|<%d>| %s", level, str);
865 static void gaa_parser (int argc, char **argv);
867 static int get_port (const struct sockaddr_storage *addr)
869 switch (addr->ss_family)
871 case AF_INET6:
872 return ntohs (((const struct sockaddr_in6 *)addr)->sin6_port);
873 case AF_INET:
874 return ntohs (((const struct sockaddr_in *)addr)->sin_port);
876 return -1;
879 static const char *addr_ntop (const struct sockaddr *sa, socklen_t salen,
880 char *buf, size_t buflen)
882 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0)
884 return buf;
886 return NULL;
890 main (int argc, char **argv)
892 int ret, n, h;
893 char topbuf[512];
894 char name[256];
895 int accept_fd;
896 struct sockaddr_storage client_address;
897 socklen_t calen;
899 #ifndef _WIN32
900 signal (SIGPIPE, SIG_IGN);
901 signal (SIGHUP, SIG_IGN);
902 signal (SIGTERM, terminate);
903 if (signal (SIGINT, terminate) == SIG_IGN)
904 signal (SIGINT, SIG_IGN); /* e.g. background process */
905 #endif
907 sockets_init ();
909 gaa_parser (argc, argv);
911 if (nodb == 0)
912 wrap_db_init ();
914 if (http == 1)
916 strcpy (name, "HTTP Server");
918 else
920 strcpy (name, "Echo Server");
923 if ((ret = gnutls_global_init ()) < 0)
925 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
926 exit (1);
928 gnutls_global_set_log_function (tls_log_func);
929 gnutls_global_set_log_level (debug);
931 if ((ret = gnutls_global_init_extra ()) < 0)
933 fprintf (stderr, "global_init_extra: %s\n", gnutls_strerror (ret));
934 exit (1);
937 /* Note that servers must generate parameters for
938 * Diffie Hellman. See gnutls_dh_params_generate(), and
939 * gnutls_dh_params_set().
941 if (generate != 0)
943 generate_rsa_params ();
944 generate_dh_primes ();
946 else if (dh_params_file)
948 read_dh_params ();
950 else
952 static_dh_params ();
955 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
957 fprintf (stderr, "memory error\n");
958 exit (1);
961 if (x509_cafile != NULL)
963 if ((ret = gnutls_certificate_set_x509_trust_file
964 (cert_cred, x509_cafile, x509ctype)) < 0)
966 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
967 GERR (ret);
968 exit (1);
970 else
972 printf ("Processed %d CA certificate(s).\n", ret);
975 #ifdef ENABLE_PKI
976 if (x509_crlfile != NULL)
978 if ((ret = gnutls_certificate_set_x509_crl_file
979 (cert_cred, x509_crlfile, x509ctype)) < 0)
981 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
982 GERR (ret);
983 exit (1);
985 else
987 printf ("Processed %d CRL(s).\n", ret);
990 #endif
992 #ifdef ENABLE_OPENPGP
993 if (pgp_keyring != NULL)
995 ret =
996 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring);
997 if (ret < 0)
999 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
1000 GERR (ret);
1004 if (pgp_trustdb != NULL)
1006 ret = gnutls_certificate_set_openpgp_trustdb (cert_cred, pgp_trustdb);
1007 if (ret < 0)
1009 fprintf (stderr, "Error setting the OpenPGP trustdb file\n");
1010 GERR (ret);
1014 if (pgp_certfile != NULL)
1015 if ((ret = gnutls_certificate_set_openpgp_key_file
1016 (cert_cred, pgp_certfile, pgp_keyfile)) < 0)
1018 fprintf (stderr,
1019 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1020 ret, pgp_certfile, pgp_keyfile);
1021 GERR (ret);
1023 #endif
1025 if (x509_certfile != NULL)
1026 if ((ret = gnutls_certificate_set_x509_key_file
1027 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
1029 fprintf (stderr,
1030 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1031 GERR (ret);
1032 exit (1);
1035 if (x509_dsacertfile != NULL)
1036 if ((ret = gnutls_certificate_set_x509_key_file
1037 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1039 fprintf (stderr, "Error reading '%s' or '%s'\n",
1040 x509_dsacertfile, x509_dsakeyfile);
1041 GERR (ret);
1042 exit (1);
1045 gnutls_certificate_set_params_function (cert_cred, get_params);
1046 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1047 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1050 /* this is a password file (created with the included srpcrypt utility)
1051 * Read README.crypt prior to using SRP.
1053 #ifdef ENABLE_SRP
1054 if (srp_passwd != NULL)
1056 gnutls_srp_allocate_server_credentials (&srp_cred);
1058 if ((ret =
1059 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1060 srp_passwd_conf)) < 0)
1062 /* only exit is this function is not disabled
1064 fprintf (stderr, "Error while setting SRP parameters\n");
1065 GERR (ret);
1068 #endif
1070 /* this is a password file
1072 #ifdef ENABLE_PSK
1073 if (psk_passwd != NULL)
1075 gnutls_psk_allocate_server_credentials (&psk_cred);
1077 if ((ret =
1078 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1080 /* only exit is this function is not disabled
1082 fprintf (stderr, "Error while setting PSK parameters\n");
1083 GERR (ret);
1086 gnutls_psk_set_server_params_function (psk_cred, get_params);
1088 #endif
1090 #ifdef ENABLE_ANON
1091 gnutls_anon_allocate_server_credentials (&dh_cred);
1092 gnutls_anon_set_server_params_function (dh_cred, get_params);
1094 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1095 #endif
1097 h = listen_socket (name, port);
1098 if (h < 0)
1099 exit (1);
1101 for (;;)
1103 listener_item *j;
1104 fd_set rd, wr;
1105 int val;
1107 FD_ZERO (&rd);
1108 FD_ZERO (&wr);
1109 n = 0;
1111 /* check for new incoming connections */
1112 FD_SET (h, &rd);
1113 n = max (n, h);
1115 /* flag which connections we are reading or writing to within the fd sets */
1116 lloopstart (listener_list, j)
1119 #ifndef _WIN32
1120 val = fcntl (j->fd, F_GETFL, 0);
1121 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1123 perror ("fcntl()");
1124 exit (1);
1126 #endif
1128 if (j->http_state == HTTP_STATE_REQUEST)
1130 FD_SET (j->fd, &rd);
1131 n = max (n, j->fd);
1133 if (j->http_state == HTTP_STATE_RESPONSE)
1135 FD_SET (j->fd, &wr);
1136 n = max (n, j->fd);
1139 lloopend (listener_list, j);
1141 /* core operation */
1142 n = select (n + 1, &rd, &wr, NULL, NULL);
1143 if (n == -1 && errno == EINTR)
1144 continue;
1145 if (n < 0)
1147 perror ("select()");
1148 exit (1);
1151 /* a new connection has arrived */
1152 if (FD_ISSET (h, &rd))
1154 gnutls_session_t tls_session;
1156 tls_session = initialize_session ();
1158 calen = sizeof (client_address);
1159 memset (&client_address, 0, calen);
1160 accept_fd = accept (h, (struct sockaddr *) &client_address, &calen);
1162 if (accept_fd < 0)
1164 perror ("accept()");
1166 else
1168 time_t tt;
1169 char *ctt;
1171 /* new list entry for the connection */
1172 lappend (listener_list);
1173 j = listener_list.tail;
1174 j->http_request = (char *) strdup ("");
1175 j->http_state = HTTP_STATE_REQUEST;
1176 j->fd = accept_fd;
1178 j->tls_session = tls_session;
1179 gnutls_transport_set_ptr (tls_session,
1180 (gnutls_transport_ptr_t) accept_fd);
1181 j->handshake_ok = 0;
1183 if (verbose == 0)
1185 tt = time (0);
1186 ctt = ctime (&tt);
1187 ctt[strlen (ctt) - 1] = 0;
1190 printf("\n* connection from %s, port %d\n",
1191 inet_ntop(AF_INET, &client_address.sin_addr, topbuf,
1192 sizeof(topbuf)), ntohs(client_address.sin_port));
1199 /* read or write to each connection as indicated by select()'s return argument */
1200 lloopstart (listener_list, j)
1202 if (FD_ISSET (j->fd, &rd))
1204 /* read partial GET request */
1205 char buf[1024];
1206 int r, ret;
1208 if (j->handshake_ok == 0)
1210 r = gnutls_handshake (j->tls_session);
1211 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1213 check_alert (j->tls_session, r);
1214 /* nothing */
1216 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1218 check_alert (j->tls_session, r);
1219 fprintf (stderr, "Error in handshake\n");
1220 GERR (r);
1224 ret =
1225 gnutls_alert_send_appropriate (j->tls_session, r);
1227 while (ret == GNUTLS_E_AGAIN);
1228 j->http_state = HTTP_STATE_CLOSING;
1230 else if (r == 0)
1232 if (gnutls_session_is_resumed (j->tls_session) != 0
1233 && verbose == 0)
1234 printf ("*** This is a resumed session\n");
1236 if (verbose == 0)
1238 printf ("\n* connection from %s, port %d\n",
1239 addr_ntop ((struct sockaddr *)&client_address, calen,
1240 topbuf, sizeof (topbuf)),
1241 get_port (&client_address));
1242 print_info (j->tls_session, NULL);
1244 j->handshake_ok = 1;
1248 if (j->handshake_ok == 1)
1250 r = gnutls_record_recv (j->tls_session, buf,
1251 min (1024, SMALL_READ_TEST));
1252 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1254 /* do nothing */
1256 else if (r <= 0)
1258 j->http_state = HTTP_STATE_CLOSING;
1259 if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1261 check_alert (j->tls_session, r);
1262 fprintf (stderr, "Error while receiving data\n");
1263 GERR (r);
1267 else
1269 j->http_request =
1270 realloc (j->http_request, j->request_length + r + 1);
1271 if (j->http_request != NULL)
1273 memcpy (j->http_request + j->request_length, buf, r);
1274 j->request_length += r;
1275 j->http_request[j->request_length] = '\0';
1277 else
1278 j->http_state = HTTP_STATE_CLOSING;
1281 /* check if we have a full HTTP header */
1283 j->http_response = NULL;
1284 if (j->http_request != NULL)
1286 if ((http == 0 && strchr (j->http_request, '\n'))
1287 || strstr (j->http_request, "\r\n\r\n")
1288 || strstr (j->http_request, "\n\n"))
1290 get_response (j->tls_session, j->http_request,
1291 &j->http_response, &j->response_length);
1292 j->http_state = HTTP_STATE_RESPONSE;
1293 j->response_written = 0;
1298 if (FD_ISSET (j->fd, &wr))
1300 /* write partial response request */
1301 int r;
1303 if (j->handshake_ok == 0)
1305 r = gnutls_handshake (j->tls_session);
1306 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1308 check_alert (j->tls_session, r);
1309 /* nothing */
1311 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1313 int ret;
1315 j->http_state = HTTP_STATE_CLOSING;
1316 check_alert (j->tls_session, r);
1317 fprintf (stderr, "Error in handshake\n");
1318 GERR (r);
1322 ret =
1323 gnutls_alert_send_appropriate (j->tls_session, r);
1325 while (ret == GNUTLS_E_AGAIN);
1327 else if (r == 0)
1329 if (gnutls_session_is_resumed (j->tls_session) != 0
1330 && verbose == 0)
1331 printf ("*** This is a resumed session\n");
1332 if (verbose == 0)
1334 printf ("- connection from %s, port %d\n",
1335 addr_ntop ((struct sockaddr*) &client_address, calen,
1336 topbuf, sizeof (topbuf)),
1337 get_port (&client_address));
1339 print_info (j->tls_session, NULL);
1341 j->handshake_ok = 1;
1345 if (j->handshake_ok == 1)
1347 /* FIXME if j->http_response == NULL? */
1348 r = gnutls_record_send (j->tls_session,
1349 j->http_response +
1350 j->response_written,
1351 min (j->response_length -
1352 j->response_written,
1353 SMALL_READ_TEST));
1354 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1356 /* do nothing */
1358 else if (r <= 0)
1360 if (http != 0)
1361 j->http_state = HTTP_STATE_CLOSING;
1362 else
1364 j->http_state = HTTP_STATE_REQUEST;
1365 free (j->http_response);
1366 j->response_length = 0;
1367 j->request_length = 0;
1368 j->http_request[0] = 0;
1371 if (r < 0)
1373 fprintf (stderr, "Error while sending data\n");
1374 GERR (r);
1376 check_alert (j->tls_session, r);
1378 else
1380 j->response_written += r;
1381 /* check if we have written a complete response */
1382 if (j->response_written == j->response_length)
1384 if (http != 0)
1385 j->http_state = HTTP_STATE_CLOSING;
1386 else
1388 j->http_state = HTTP_STATE_REQUEST;
1389 free (j->http_response);
1390 j->response_length = 0;
1391 j->request_length = 0;
1392 j->http_request[0] = 0;
1399 lloopend (listener_list, j);
1401 /* loop through all connections, closing those that are in error */
1402 lloopstart (listener_list, j)
1404 if (j->http_state == HTTP_STATE_CLOSING)
1406 ldeleteinc (listener_list, j);
1409 lloopend (listener_list, j);
1413 gnutls_certificate_free_credentials (cert_cred);
1415 #ifdef ENABLE_SRP
1416 if (srp_cred)
1417 gnutls_srp_free_server_credentials (srp_cred);
1418 #endif
1420 #ifdef ENABLE_PSK
1421 if (psk_cred)
1422 gnutls_psk_free_server_credentials (psk_cred);
1423 #endif
1425 #ifdef ENABLE_ANON
1426 gnutls_anon_free_server_credentials (dh_cred);
1427 #endif
1429 if (nodb == 0)
1430 wrap_db_deinit ();
1431 gnutls_global_deinit ();
1433 return 0;
1437 void
1438 gaa_parser (int argc, char **argv)
1440 if (gaa (argc, argv, &info) != -1)
1442 fprintf (stderr,
1443 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1444 exit (1);
1447 disable_client_cert = info.disable_client_cert;
1448 require_cert = info.require_cert;
1449 debug = info.debug;
1450 verbose = info.quiet;
1451 nodb = info.nodb;
1453 if (info.http == 0)
1454 http = 0;
1455 else
1456 http = 1;
1458 if (info.fmtder == 0)
1459 x509ctype = GNUTLS_X509_FMT_PEM;
1460 else
1461 x509ctype = GNUTLS_X509_FMT_DER;
1463 if (info.generate == 0)
1464 generate = 0;
1465 else
1466 generate = 1;
1468 dh_params_file = info.dh_params_file;
1470 port = info.port;
1472 x509_certfile = info.x509_certfile;
1473 x509_keyfile = info.x509_keyfile;
1474 x509_dsacertfile = info.x509_dsacertfile;
1475 x509_dsakeyfile = info.x509_dsakeyfile;
1476 x509_cafile = info.x509_cafile;
1477 x509_crlfile = info.x509_crlfile;
1478 pgp_certfile = info.pgp_certfile;
1479 pgp_keyfile = info.pgp_keyfile;
1480 srp_passwd = info.srp_passwd;
1481 srp_passwd_conf = info.srp_passwd_conf;
1483 psk_passwd = info.psk_passwd;
1485 pgp_keyring = info.pgp_keyring;
1486 pgp_trustdb = info.pgp_trustdb;
1488 parse_protocols (info.proto, info.nproto, protocol_priority);
1489 parse_ciphers (info.ciphers, info.nciphers, cipher_priority);
1490 parse_macs (info.macs, info.nmacs, mac_priority);
1491 parse_ctypes (info.ctype, info.nctype, cert_type_priority);
1492 parse_kx (info.kx, info.nkx, kx_priority);
1493 parse_comp (info.comp, info.ncomp, comp_priority);
1495 #ifdef ENABLE_AUTHZ
1497 size_t authz_idx = 0;
1498 if (info.authz_x509_attr_cert)
1499 authz_server_formats[authz_idx++] = GNUTLS_AUTHZ_X509_ATTR_CERT;
1500 if (info.authz_saml_assertion)
1501 authz_server_formats[authz_idx++] = GNUTLS_AUTHZ_SAML_ASSERTION;
1503 #endif
1506 void
1507 serv_version (void)
1509 const char *v = gnutls_check_version (NULL);
1511 printf ("gnutls-serv (GnuTLS) %s\n", LIBGNUTLS_VERSION);
1512 if (strcmp (v, LIBGNUTLS_VERSION) != 0)
1513 printf ("libgnutls %s\n", v);
1516 /* session resuming support */
1518 #define SESSION_ID_SIZE 32
1519 #define SESSION_DATA_SIZE 1024
1521 typedef struct
1523 char session_id[SESSION_ID_SIZE];
1524 unsigned int session_id_size;
1526 char session_data[SESSION_DATA_SIZE];
1527 unsigned int session_data_size;
1528 } CACHE;
1530 static CACHE *cache_db;
1531 int cache_db_ptr = 0;
1533 static void
1534 wrap_db_init (void)
1537 /* allocate cache_db */
1538 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1541 static void
1542 wrap_db_deinit (void)
1546 static int
1547 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1550 if (cache_db == NULL)
1551 return -1;
1553 if (key.size > SESSION_ID_SIZE)
1554 return -1;
1555 if (data.size > SESSION_DATA_SIZE)
1556 return -1;
1558 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1559 cache_db[cache_db_ptr].session_id_size = key.size;
1561 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1562 cache_db[cache_db_ptr].session_data_size = data.size;
1564 cache_db_ptr++;
1565 cache_db_ptr %= ssl_session_cache;
1567 return 0;
1570 static gnutls_datum_t
1571 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1573 gnutls_datum_t res = { NULL, 0 };
1574 int i;
1576 if (cache_db == NULL)
1577 return res;
1579 for (i = 0; i < ssl_session_cache; i++)
1581 if (key.size == cache_db[i].session_id_size &&
1582 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1586 res.size = cache_db[i].session_data_size;
1588 res.data = gnutls_malloc (res.size);
1589 if (res.data == NULL)
1590 return res;
1592 memcpy (res.data, cache_db[i].session_data, res.size);
1594 return res;
1597 return res;
1600 static int
1601 wrap_db_delete (void *dbf, gnutls_datum_t key)
1603 int i;
1605 if (cache_db == NULL)
1606 return -1;
1608 for (i = 0; i < ssl_session_cache; i++)
1610 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1611 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1614 cache_db[i].session_id_size = 0;
1615 cache_db[i].session_data_size = 0;
1617 return 0;
1621 return -1;
1625 void
1626 print_serv_license (void)
1628 fputs ("\nCopyright (C) 2001-2003 Paul Sheer, Nikos Mavroyanopoulos\n"
1629 "\nCopyright (C) 2004 Free Software Foundation\n"
1630 "This program is free software; you can redistribute it and/or modify \n"
1631 "it under the terms of the GNU General Public License as published by \n"
1632 "the Free Software Foundation; either version 2 of the License, or \n"
1633 "(at your option) any later version. \n" "\n"
1634 "This program is distributed in the hope that it will be useful, \n"
1635 "but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
1636 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n"
1637 "GNU General Public License for more details. \n" "\n"
1638 "You should have received a copy of the GNU General Public License \n"
1639 "along with this program; if not, write to the Free Software \n"
1640 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",
1641 stdout);