Add psktool to @direntry. Alphasort @direntry.
[gnutls.git] / src / serv.c
blobc03c191fc5b11a2ad38e6203af6ebffffbdc1f9a
1 /*
2 * Copyright (C) 2004, 2006, 2007, 2008 Free Software Foundation
3 * Copyright (C) 2001,2002 Paul Sheer
4 * Portions Copyright (C) 2002,2003 Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * GNUTLS is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * GNUTLS is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* This server is heavily modified for GNUTLS by Nikos Mavrogiannopoulos
23 * (which means it is quite unreadable)
26 #include "common.h"
27 #include "serv-gaa.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <string.h>
33 #include <gnutls/gnutls.h>
34 #include <gcrypt.h>
35 #include <gnutls/extra.h>
36 #include <gnutls/openpgp.h>
37 #include <sys/time.h>
38 #include <fcntl.h>
39 #include <list.h>
41 #if defined _WIN32 || defined __WIN32__
42 int _win_select(int max_fd, fd_set * rfds, fd_set * wfds, fd_set * efds,
43 const struct timeval *tv);
44 #define select _win_select
45 #endif
47 #include "error.h"
48 #include "read-file.h"
50 #include "getaddrinfo.h"
52 /* konqueror cannot handle sending the page in multiple
53 * pieces.
55 /* global stuff */
56 static int generate = 0;
57 static int http = 0;
58 static int port = 0;
59 static int x509ctype;
60 static int debug;
62 int verbose;
63 static int nodb;
64 int require_cert;
65 int disable_client_cert;
67 char *psk_passwd;
68 char *srp_passwd;
69 char *srp_passwd_conf;
70 char *pgp_keyring;
71 char *pgp_keyfile;
72 char *pgp_certfile;
73 char *x509_keyfile;
74 char *x509_certfile;
75 char *x509_dsakeyfile;
76 char *x509_dsacertfile;
77 char *x509_cafile;
78 char *dh_params_file;
79 char *x509_crlfile = NULL;
81 /* end of globals */
83 /* This is a sample TCP echo server.
84 * This will behave as an http server if any argument in the
85 * command line is present
88 #define SMALL_READ_TEST (2147483647)
90 #define SA struct sockaddr
91 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
92 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
93 #define MAX_BUF 1024
95 #undef max
96 #define max(x,y) ((x) > (y) ? (x) : (y))
97 #undef min
98 #define min(x,y) ((x) < (y) ? (x) : (y))
101 #define HTTP_END "</BODY></HTML>\n\n"
103 #define HTTP_UNIMPLEMENTED "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML><HEAD>\r\n<TITLE>501 Method Not Implemented</TITLE>\r\n</HEAD><BODY>\r\n<H1>Method Not Implemented</H1>\r\n<HR>\r\n</BODY></HTML>\r\n"
104 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
106 #define HTTP_BEGIN HTTP_OK \
107 "\n" \
108 "<HTML><BODY>\n" \
109 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
110 "GNUTLS</a></H1></CENTER>\n\n"
112 #define RENEGOTIATE
114 /* These are global */
115 gnutls_srp_server_credentials_t srp_cred = NULL;
116 gnutls_psk_server_credentials_t psk_cred = NULL;
117 gnutls_anon_server_credentials_t dh_cred = NULL;
118 gnutls_certificate_credentials_t cert_cred = NULL;
120 static gaainfo info;
122 const int ssl_session_cache = 128;
124 static void wrap_db_init (void);
125 static void wrap_db_deinit (void);
126 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
127 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
128 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
131 #define HTTP_STATE_REQUEST 1
132 #define HTTP_STATE_RESPONSE 2
133 #define HTTP_STATE_CLOSING 3
135 LIST_TYPE_DECLARE (listener_item, char *http_request;
136 char *http_response; int request_length;
137 int response_length; int response_written;
138 int http_state;
139 int fd; gnutls_session_t tls_session; int handshake_ok;);
141 static const char *
142 safe_strerror (int value)
144 const char *ret = gnutls_strerror (value);
145 if (ret == NULL)
146 ret = str_unknown;
147 return ret;
150 static void
151 listener_free (listener_item * j)
154 if (j->http_request)
155 free (j->http_request);
156 if (j->http_response)
157 free (j->http_response);
158 if (j->fd >= 0)
160 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
161 shutdown (j->fd, 2);
162 close (j->fd);
163 gnutls_deinit (j->tls_session);
168 /* we use primes up to 1024 in this server.
169 * otherwise we should add them here.
172 gnutls_dh_params_t dh_params = NULL;
173 gnutls_rsa_params_t rsa_params = NULL;
175 static int
176 generate_dh_primes (void)
178 int prime_bits = 768;
180 if (gnutls_dh_params_init (&dh_params) < 0)
182 fprintf (stderr, "Error in dh parameter initialization\n");
183 exit (1);
186 /* Generate Diffie Hellman parameters - for use with DHE
187 * kx algorithms. These should be discarded and regenerated
188 * once a week or once a month. Depends on the
189 * security requirements.
191 printf
192 ("Generating Diffie Hellman parameters [%d]. Please wait...\n",
193 prime_bits);
194 fflush (stdout);
196 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
198 fprintf (stderr, "Error in prime generation\n");
199 exit (1);
202 return 0;
205 static void
206 read_dh_params (void)
208 char tmpdata[2048];
209 int size;
210 gnutls_datum_t params;
211 FILE *fd;
213 if (gnutls_dh_params_init (&dh_params) < 0)
215 fprintf (stderr, "Error in dh parameter initialization\n");
216 exit (1);
219 /* read the params file
221 fd = fopen (dh_params_file, "r");
222 if (fd == NULL)
224 fprintf (stderr, "Could not open %s\n", dh_params_file);
225 exit (1);
228 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
229 tmpdata[size] = 0;
230 fclose (fd);
232 params.data = (unsigned char *) tmpdata;
233 params.size = size;
235 size =
236 gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
238 if (size < 0)
240 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
241 exit (1);
244 printf ("Read Diffie Hellman parameters.\n");
245 fflush (stdout);
249 static char pkcs3[] =
250 "-----BEGIN DH PARAMETERS-----\n"
251 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
252 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
253 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
254 "-----END DH PARAMETERS-----\n";
256 static int
257 static_dh_params (void)
259 gnutls_datum_t params = { pkcs3, sizeof (pkcs3) };
260 int ret;
262 if (gnutls_dh_params_init (&dh_params) < 0)
264 fprintf (stderr, "Error in dh parameter initialization\n");
265 exit (1);
268 ret = gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
270 if (ret < 0)
272 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
273 exit (1);
276 printf ("Set static Diffie Hellman parameters, consider --dhparams.\n");
278 return 0;
281 static int
282 get_params (gnutls_session_t session, gnutls_params_type_t type,
283 gnutls_params_st * st)
286 if (type == GNUTLS_PARAMS_RSA_EXPORT)
288 if (rsa_params == NULL)
289 return -1;
290 st->params.rsa_export = rsa_params;
292 else if (type == GNUTLS_PARAMS_DH)
294 if (dh_params == NULL)
295 return -1;
296 st->params.dh = dh_params;
298 else
299 return -1;
301 st->type = type;
302 st->deinit = 0;
304 return 0;
307 static int
308 generate_rsa_params (void)
310 if (gnutls_rsa_params_init (&rsa_params) < 0)
312 fprintf (stderr, "Error in rsa parameter initialization\n");
313 exit (1);
316 /* Generate RSA parameters - for use with RSA-export
317 * cipher suites. These should be discarded and regenerated
318 * once a day, once every 500 transactions etc. Depends on the
319 * security requirements.
321 printf ("Generating temporary RSA parameters. Please wait...\n");
322 fflush (stdout);
324 if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
326 fprintf (stderr, "Error in rsa parameter generation\n");
327 exit (1);
330 return 0;
333 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
335 static int protocol_priority[PRI_MAX];
336 static int kx_priority[PRI_MAX];
337 static int cipher_priority[PRI_MAX];
338 static int comp_priority[PRI_MAX];
339 static int mac_priority[PRI_MAX];
340 static int cert_type_priority[PRI_MAX];
342 #if ENABLE_OPRFI
344 oprfi_callback (gnutls_session_t session,
345 void *userdata,
346 size_t oprfi_len,
347 const unsigned char *in_oprfi,
348 unsigned char *out_oprfi)
350 size_t ourlen = strlen (info.opaque_prf_input);
351 size_t i;
353 printf ("- Received Opaque PRF data of %d bytes\n", oprfi_len);
354 printf (" data: ");
355 for (i = 0; i < oprfi_len; i++)
356 printf ("%02x", in_oprfi[i]);
357 printf ("\n");
359 memset(out_oprfi, 0, oprfi_len);
360 strncpy (out_oprfi, info.opaque_prf_input, oprfi_len);
362 return 0;
364 #endif
366 gnutls_session_t
367 initialize_session (void)
369 gnutls_session_t session;
370 const char *err;
372 gnutls_init (&session, GNUTLS_SERVER);
374 /* allow the use of private ciphersuites.
376 gnutls_handshake_set_private_extensions (session, 1);
378 if (nodb == 0)
380 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
381 gnutls_db_set_remove_function (session, wrap_db_delete);
382 gnutls_db_set_store_function (session, wrap_db_store);
383 gnutls_db_set_ptr (session, NULL);
386 if (gnutls_priority_set_direct (session, info.priorities, &err) < 0)
388 fprintf(stderr, "Syntax error at: %s\n", err);
389 exit(1);
392 if (cipher_priority[0])
393 gnutls_cipher_set_priority (session, cipher_priority);
394 if (comp_priority[0])
395 gnutls_compression_set_priority (session, comp_priority);
396 if (kx_priority[0])
397 gnutls_kx_set_priority (session, kx_priority);
398 if (protocol_priority[0])
399 gnutls_protocol_set_priority (session, protocol_priority);
400 if (mac_priority[0])
401 gnutls_mac_set_priority (session, mac_priority);
402 if (cert_type_priority[0])
403 gnutls_certificate_type_set_priority (session, cert_type_priority);
405 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
407 if (srp_cred != NULL)
408 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
410 if (psk_cred != NULL)
411 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
413 if (cert_cred != NULL)
414 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
416 if (disable_client_cert)
417 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
418 else {
419 if (require_cert)
420 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
421 else
422 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
425 /* Set maximum compatibility mode. This is only suggested on public webservers
426 * that need to trade security for compatibility
428 gnutls_session_enable_compatibility_mode( session);
430 #ifdef ENABLE_OPRFI
431 if (info.opaque_prf_input)
432 gnutls_oprfi_enable_server (session, oprfi_callback, NULL);
433 #endif
435 return session;
438 #include <gnutls/x509.h>
440 static const char DEFAULT_DATA[] =
441 "This is the default message reported by the GnuTLS implementation. "
442 "For more information please visit "
443 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
445 /* Creates html with the current session information.
447 #define tmp2 &http_buffer[strlen(http_buffer)]
448 char *
449 peer_print_info (gnutls_session_t session, int *ret_length, const char *header)
451 const char *tmp;
452 unsigned char sesid[32];
453 size_t i, sesid_size;
454 char *http_buffer;
455 gnutls_kx_algorithm_t kx_alg;
456 size_t len = 5 * 1024 + strlen (header);
457 char *crtinfo = NULL;
458 size_t ncrtinfo = 0;
460 if (verbose != 0)
462 http_buffer = malloc (len);
463 if (http_buffer == NULL)
464 return NULL;
466 strcpy (http_buffer, HTTP_BEGIN);
467 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
468 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
469 HTTP_END);
470 *ret_length =
471 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
472 return http_buffer;
476 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
478 const gnutls_datum_t *cert_list;
479 unsigned int cert_list_size = 0;
480 size_t i;
482 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
484 for (i = 0; i < cert_list_size; i++)
486 gnutls_x509_crt_t cert;
487 gnutls_datum_t info;
489 if (gnutls_x509_crt_init (&cert) == 0 &&
490 gnutls_x509_crt_import (cert, &cert_list[i],
491 GNUTLS_X509_FMT_DER) == 0 &&
492 gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &info) == 0)
494 const char *post = "</PRE><P><PRE>";
496 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
497 strlen (post) + 1);
498 if (crtinfo == NULL)
499 return NULL;
500 memcpy (crtinfo + ncrtinfo, info.data, info.size);
501 ncrtinfo += info.size;
502 memcpy (crtinfo + ncrtinfo, post, strlen (post));
503 ncrtinfo += strlen (post);
504 crtinfo[ncrtinfo] = '\0';
505 gnutls_free (info.data);
510 http_buffer = malloc (len);
511 if (http_buffer == NULL)
512 return NULL;
514 strcpy (http_buffer, HTTP_BEGIN);
516 /* print session_id */
517 gnutls_session_get_id (session, sesid, &sesid_size);
518 sprintf (tmp2, "\n<p>Session ID: <i>");
519 for (i = 0; i < sesid_size; i++)
520 sprintf (tmp2, "%.2X", sesid[i]);
521 sprintf (tmp2, "</i></p>\n");
522 sprintf (tmp2,
523 "<h5>If your browser supports session resuming, then you should see the "
524 "same session ID, when you press the <b>reload</b> button.</h5>\n");
526 /* Here unlike print_info() we use the kx algorithm to distinguish
527 * the functions to call.
530 char dns[256];
531 size_t dns_size = sizeof (dns);
532 unsigned int type;
534 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
536 sprintf (tmp2, "\n<p>Server Name: %s</p>\n", dns);
541 kx_alg = gnutls_kx_get (session);
543 /* print srp specific data */
544 #ifdef ENABLE_SRP
545 if (kx_alg == GNUTLS_KX_SRP)
547 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
548 gnutls_srp_server_get_username (session));
550 #endif
552 #ifdef ENABLE_PSK
553 if (kx_alg == GNUTLS_KX_PSK)
555 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
556 gnutls_psk_server_get_username (session));
558 #endif
560 #ifdef ENABLE_ANON
561 if (kx_alg == GNUTLS_KX_ANON_DH)
563 sprintf (tmp2,
564 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
565 gnutls_dh_get_prime_bits (session));
567 #endif
569 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
571 sprintf (tmp2,
572 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
573 gnutls_dh_get_prime_bits (session));
576 /* print session information */
577 strcat (http_buffer, "<P>\n");
579 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
580 if (tmp == NULL)
581 tmp = str_unknown;
582 sprintf (tmp2,
583 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
584 tmp);
586 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
588 tmp =
589 gnutls_certificate_type_get_name (gnutls_certificate_type_get
590 (session));
591 if (tmp == NULL)
592 tmp = str_unknown;
593 sprintf (tmp2, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
596 tmp = gnutls_kx_get_name (kx_alg);
597 if (tmp == NULL)
598 tmp = str_unknown;
599 sprintf (tmp2, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
601 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
602 if (tmp == NULL)
603 tmp = str_unknown;
604 sprintf (tmp2, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
606 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
607 if (tmp == NULL)
608 tmp = str_unknown;
609 sprintf (tmp2, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
611 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
612 if (tmp == NULL)
613 tmp = str_unknown;
614 sprintf (tmp2, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
616 tmp = gnutls_cipher_suite_get_name (kx_alg,
617 gnutls_cipher_get (session),
618 gnutls_mac_get (session));
619 if (tmp == NULL)
620 tmp = str_unknown;
621 sprintf (tmp2, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
622 tmp);
624 if (crtinfo)
626 strcat (http_buffer, "<hr><PRE>");
627 strcat (http_buffer, crtinfo);
628 strcat (http_buffer, "\n</PRE>\n");
631 strcat (http_buffer, "<hr><P>Your HTTP header was:<PRE>");
632 strcat (http_buffer, header);
633 strcat (http_buffer, "</PRE></P>");
635 strcat (http_buffer, "\n" HTTP_END);
637 *ret_length = strlen (http_buffer);
639 return http_buffer;
642 static int
643 listen_socket (const char *name, int listen_port)
645 struct addrinfo hints, *res, *ptr;
646 char portname[6];
647 int s;
648 int yes;
650 snprintf (portname, sizeof (portname), "%d", listen_port);
651 memset (&hints, 0, sizeof (hints));
652 hints.ai_socktype = SOCK_STREAM;
653 hints.ai_flags = AI_PASSIVE;
655 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
657 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
658 return -1;
660 s = -1;
662 for (ptr = res; (ptr != NULL) && (s == -1); ptr = ptr->ai_next)
664 if ((s = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) < 0)
666 perror ("socket() failed");
667 continue;
670 yes = 1;
671 if (setsockopt
672 (s, SOL_SOCKET, SO_REUSEADDR, (const void *) &yes, sizeof (yes)) < 0)
674 perror ("setsockopt() failed");
675 failed:
676 close (s);
677 s = -1;
678 continue;
681 if (bind (s, res->ai_addr, res->ai_addrlen) < 0)
683 perror ("bind() failed");
684 goto failed;
687 if (listen (s, 10) < 0)
689 perror ("listen() failed");
690 goto failed;
694 freeaddrinfo (res);
695 if (s == -1)
697 return -1;
700 printf ("%s ready. Listening to port '%s'.\n\n", name, portname);
701 return s;
704 static void
705 get_response (gnutls_session_t session, char *request,
706 char **response, int *response_length)
708 char *p, *h;
710 if (http != 0)
712 if (strncmp (request, "GET ", 4))
713 goto unimplemented;
715 if (!(h = strchr (request, '\n')))
716 goto unimplemented;
718 *h++ = '\0';
719 while (*h == '\r' || *h == '\n')
720 h++;
722 if (!(p = strchr (request + 4, ' ')))
723 goto unimplemented;
724 *p = '\0';
726 /* *response = peer_print_info(session, request+4, h, response_length); */
727 if (http != 0)
729 *response = peer_print_info (session, response_length, h);
731 else
733 *response = strdup (request);
734 *response_length = ((*response) ? strlen (*response) : 0);
737 return;
739 unimplemented:
740 *response = strdup (HTTP_UNIMPLEMENTED);
741 *response_length = ((*response) ? strlen (*response) : 0);
744 void
745 terminate (int sig)
747 fprintf (stderr, "Exiting via signal %d\n", sig);
748 exit (1);
752 static void
753 check_alert (gnutls_session_t session, int ret)
755 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
756 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
758 int last_alert = gnutls_alert_get (session);
759 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
760 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
761 printf
762 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
763 else
764 printf ("* Received alert '%d': %s.\n", last_alert,
765 gnutls_alert_get_name (last_alert));
769 static void
770 tls_log_func (int level, const char *str)
772 fprintf (stderr, "|<%d>| %s", level, str);
775 static void gaa_parser (int argc, char **argv);
777 static int get_port (const struct sockaddr_storage *addr)
779 switch (addr->ss_family)
781 case AF_INET6:
782 return ntohs (((const struct sockaddr_in6 *)addr)->sin6_port);
783 case AF_INET:
784 return ntohs (((const struct sockaddr_in *)addr)->sin_port);
786 return -1;
789 static const char *addr_ntop (const struct sockaddr *sa, socklen_t salen,
790 char *buf, size_t buflen)
792 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0)
794 return buf;
796 return NULL;
800 main (int argc, char **argv)
802 int ret, n, h;
803 char topbuf[512];
804 char name[256];
805 int accept_fd;
806 struct sockaddr_storage client_address;
807 socklen_t calen;
809 #ifndef _WIN32
810 signal (SIGPIPE, SIG_IGN);
811 signal (SIGHUP, SIG_IGN);
812 signal (SIGTERM, terminate);
813 if (signal (SIGINT, terminate) == SIG_IGN)
814 signal (SIGINT, SIG_IGN); /* e.g. background process */
815 #endif
817 sockets_init ();
819 gaa_parser (argc, argv);
821 if (nodb == 0)
822 wrap_db_init ();
824 if (http == 1)
826 strcpy (name, "HTTP Server");
828 else
830 strcpy (name, "Echo Server");
833 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
835 if ((ret = gnutls_global_init ()) < 0)
837 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
838 exit (1);
840 gnutls_global_set_log_function (tls_log_func);
841 gnutls_global_set_log_level (debug);
843 /* Note that servers must generate parameters for
844 * Diffie Hellman. See gnutls_dh_params_generate(), and
845 * gnutls_dh_params_set().
847 if (generate != 0)
849 generate_rsa_params ();
850 generate_dh_primes ();
852 else if (dh_params_file)
854 read_dh_params ();
856 else
858 static_dh_params ();
861 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
863 fprintf (stderr, "memory error\n");
864 exit (1);
867 if (x509_cafile != NULL)
869 if ((ret = gnutls_certificate_set_x509_trust_file
870 (cert_cred, x509_cafile, x509ctype)) < 0)
872 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
873 GERR (ret);
874 exit (1);
876 else
878 printf ("Processed %d CA certificate(s).\n", ret);
881 #ifdef ENABLE_PKI
882 if (x509_crlfile != NULL)
884 if ((ret = gnutls_certificate_set_x509_crl_file
885 (cert_cred, x509_crlfile, x509ctype)) < 0)
887 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
888 GERR (ret);
889 exit (1);
891 else
893 printf ("Processed %d CRL(s).\n", ret);
896 #endif
898 #ifdef ENABLE_OPENPGP
899 if (pgp_keyring != NULL)
901 ret =
902 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring, GNUTLS_OPENPGP_FMT_BASE64);
903 if (ret < 0)
905 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
906 GERR (ret);
910 if (pgp_certfile != NULL)
912 if (info.pgp_subkey != NULL)
913 ret = gnutls_certificate_set_openpgp_key_file2
914 (cert_cred, pgp_certfile, pgp_keyfile, info.pgp_subkey, GNUTLS_OPENPGP_FMT_BASE64);
915 else
916 ret = gnutls_certificate_set_openpgp_key_file
917 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64);
919 if (ret < 0)
921 fprintf (stderr,
922 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
923 ret, pgp_certfile, pgp_keyfile);
924 GERR (ret);
927 #endif
929 if (x509_certfile != NULL)
930 if ((ret = gnutls_certificate_set_x509_key_file
931 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
933 fprintf (stderr,
934 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
935 GERR (ret);
936 exit (1);
939 if (x509_dsacertfile != NULL)
940 if ((ret = gnutls_certificate_set_x509_key_file
941 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
943 fprintf (stderr, "Error reading '%s' or '%s'\n",
944 x509_dsacertfile, x509_dsakeyfile);
945 GERR (ret);
946 exit (1);
949 gnutls_certificate_set_params_function (cert_cred, get_params);
950 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
951 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
954 /* this is a password file (created with the included srpcrypt utility)
955 * Read README.crypt prior to using SRP.
957 #ifdef ENABLE_SRP
958 if (srp_passwd != NULL)
960 gnutls_srp_allocate_server_credentials (&srp_cred);
962 if ((ret =
963 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
964 srp_passwd_conf)) < 0)
966 /* only exit is this function is not disabled
968 fprintf (stderr, "Error while setting SRP parameters\n");
969 GERR (ret);
972 #endif
974 /* this is a password file
976 #ifdef ENABLE_PSK
977 if (psk_passwd != NULL)
979 gnutls_psk_allocate_server_credentials (&psk_cred);
981 if ((ret =
982 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
984 /* only exit is this function is not disabled
986 fprintf (stderr, "Error while setting PSK parameters\n");
987 GERR (ret);
990 if (info.psk_hint)
992 ret = gnutls_psk_set_server_credentials_hint (psk_cred,
993 info.psk_hint);
994 if (ret)
996 fprintf (stderr, "Error setting PSK identity hint.\n");
997 GERR (ret);
1001 gnutls_psk_set_server_params_function (psk_cred, get_params);
1003 #endif
1005 #ifdef ENABLE_ANON
1006 gnutls_anon_allocate_server_credentials (&dh_cred);
1007 gnutls_anon_set_server_params_function (dh_cred, get_params);
1009 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1010 #endif
1012 h = listen_socket (name, port);
1013 if (h < 0)
1014 exit (1);
1016 for (;;)
1018 listener_item *j;
1019 fd_set rd, wr;
1020 int val;
1022 FD_ZERO (&rd);
1023 FD_ZERO (&wr);
1024 n = 0;
1026 /* check for new incoming connections */
1027 FD_SET (h, &rd);
1028 n = max (n, h);
1030 /* flag which connections we are reading or writing to within the fd sets */
1031 lloopstart (listener_list, j)
1034 #ifndef _WIN32
1035 val = fcntl (j->fd, F_GETFL, 0);
1036 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1038 perror ("fcntl()");
1039 exit (1);
1041 #endif
1043 if (j->http_state == HTTP_STATE_REQUEST)
1045 FD_SET (j->fd, &rd);
1046 n = max (n, j->fd);
1048 if (j->http_state == HTTP_STATE_RESPONSE)
1050 FD_SET (j->fd, &wr);
1051 n = max (n, j->fd);
1054 lloopend (listener_list, j);
1056 /* core operation */
1057 n = select (n + 1, &rd, &wr, NULL, NULL);
1058 if (n == -1 && errno == EINTR)
1059 continue;
1060 if (n < 0)
1062 perror ("select()");
1063 exit (1);
1066 /* a new connection has arrived */
1067 if (FD_ISSET (h, &rd))
1069 gnutls_session_t tls_session;
1071 tls_session = initialize_session ();
1073 calen = sizeof (client_address);
1074 memset (&client_address, 0, calen);
1075 accept_fd = accept (h, (struct sockaddr *) &client_address, &calen);
1077 if (accept_fd < 0)
1079 perror ("accept()");
1081 else
1083 time_t tt;
1084 char *ctt;
1086 /* new list entry for the connection */
1087 lappend (listener_list);
1088 j = listener_list.tail;
1089 j->http_request = (char *) strdup ("");
1090 j->http_state = HTTP_STATE_REQUEST;
1091 j->fd = accept_fd;
1093 j->tls_session = tls_session;
1094 gnutls_transport_set_ptr (tls_session,
1095 (gnutls_transport_ptr_t) accept_fd);
1096 j->handshake_ok = 0;
1098 if (verbose == 0)
1100 tt = time (0);
1101 ctt = ctime (&tt);
1102 ctt[strlen (ctt) - 1] = 0;
1105 printf("\n* connection from %s, port %d\n",
1106 inet_ntop(AF_INET, &client_address.sin_addr, topbuf,
1107 sizeof(topbuf)), ntohs(client_address.sin_port));
1114 /* read or write to each connection as indicated by select()'s return argument */
1115 lloopstart (listener_list, j)
1117 if (FD_ISSET (j->fd, &rd))
1119 /* read partial GET request */
1120 char buf[1024];
1121 int r, ret;
1123 if (j->handshake_ok == 0)
1125 r = gnutls_handshake (j->tls_session);
1126 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1128 check_alert (j->tls_session, r);
1129 /* nothing */
1131 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1133 check_alert (j->tls_session, r);
1134 fprintf (stderr, "Error in handshake\n");
1135 GERR (r);
1139 ret =
1140 gnutls_alert_send_appropriate (j->tls_session, r);
1142 while (ret == GNUTLS_E_AGAIN);
1143 j->http_state = HTTP_STATE_CLOSING;
1145 else if (r == 0)
1147 if (gnutls_session_is_resumed (j->tls_session) != 0
1148 && verbose == 0)
1149 printf ("*** This is a resumed session\n");
1151 if (verbose == 0)
1153 printf ("\n* connection from %s, port %d\n",
1154 addr_ntop ((struct sockaddr *)&client_address, calen,
1155 topbuf, sizeof (topbuf)),
1156 get_port (&client_address));
1157 print_info (j->tls_session, NULL, 1);
1159 j->handshake_ok = 1;
1163 if (j->handshake_ok == 1)
1165 r = gnutls_record_recv (j->tls_session, buf,
1166 min (1024, SMALL_READ_TEST));
1167 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1169 /* do nothing */
1171 else if (r <= 0)
1173 j->http_state = HTTP_STATE_CLOSING;
1174 if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1176 check_alert (j->tls_session, r);
1177 fprintf (stderr, "Error while receiving data\n");
1178 GERR (r);
1182 else
1184 j->http_request =
1185 realloc (j->http_request, j->request_length + r + 1);
1186 if (j->http_request != NULL)
1188 memcpy (j->http_request + j->request_length, buf, r);
1189 j->request_length += r;
1190 j->http_request[j->request_length] = '\0';
1192 else
1193 j->http_state = HTTP_STATE_CLOSING;
1196 /* check if we have a full HTTP header */
1198 j->http_response = NULL;
1199 if (j->http_request != NULL)
1201 if ((http == 0 && strchr (j->http_request, '\n'))
1202 || strstr (j->http_request, "\r\n\r\n")
1203 || strstr (j->http_request, "\n\n"))
1205 get_response (j->tls_session, j->http_request,
1206 &j->http_response, &j->response_length);
1207 j->http_state = HTTP_STATE_RESPONSE;
1208 j->response_written = 0;
1213 if (FD_ISSET (j->fd, &wr))
1215 /* write partial response request */
1216 int r;
1218 if (j->handshake_ok == 0)
1220 r = gnutls_handshake (j->tls_session);
1221 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1223 check_alert (j->tls_session, r);
1224 /* nothing */
1226 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1228 int ret;
1230 j->http_state = HTTP_STATE_CLOSING;
1231 check_alert (j->tls_session, r);
1232 fprintf (stderr, "Error in handshake\n");
1233 GERR (r);
1237 ret =
1238 gnutls_alert_send_appropriate (j->tls_session, r);
1240 while (ret == GNUTLS_E_AGAIN);
1242 else if (r == 0)
1244 if (gnutls_session_is_resumed (j->tls_session) != 0
1245 && verbose == 0)
1246 printf ("*** This is a resumed session\n");
1247 if (verbose == 0)
1249 printf ("- connection from %s, port %d\n",
1250 addr_ntop ((struct sockaddr*) &client_address, calen,
1251 topbuf, sizeof (topbuf)),
1252 get_port (&client_address));
1254 print_info (j->tls_session, NULL, 1);
1256 j->handshake_ok = 1;
1260 if (j->handshake_ok == 1)
1262 /* FIXME if j->http_response == NULL? */
1263 r = gnutls_record_send (j->tls_session,
1264 j->http_response +
1265 j->response_written,
1266 min (j->response_length -
1267 j->response_written,
1268 SMALL_READ_TEST));
1269 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1271 /* do nothing */
1273 else if (r <= 0)
1275 if (http != 0)
1276 j->http_state = HTTP_STATE_CLOSING;
1277 else
1279 j->http_state = HTTP_STATE_REQUEST;
1280 free (j->http_response);
1281 j->response_length = 0;
1282 j->request_length = 0;
1283 j->http_request[0] = 0;
1286 if (r < 0)
1288 fprintf (stderr, "Error while sending data\n");
1289 GERR (r);
1291 check_alert (j->tls_session, r);
1293 else
1295 j->response_written += r;
1296 /* check if we have written a complete response */
1297 if (j->response_written == j->response_length)
1299 if (http != 0)
1300 j->http_state = HTTP_STATE_CLOSING;
1301 else
1303 j->http_state = HTTP_STATE_REQUEST;
1304 free (j->http_response);
1305 j->response_length = 0;
1306 j->request_length = 0;
1307 j->http_request[0] = 0;
1314 lloopend (listener_list, j);
1316 /* loop through all connections, closing those that are in error */
1317 lloopstart (listener_list, j)
1319 if (j->http_state == HTTP_STATE_CLOSING)
1321 ldeleteinc (listener_list, j);
1324 lloopend (listener_list, j);
1328 gnutls_certificate_free_credentials (cert_cred);
1330 #ifdef ENABLE_SRP
1331 if (srp_cred)
1332 gnutls_srp_free_server_credentials (srp_cred);
1333 #endif
1335 #ifdef ENABLE_PSK
1336 if (psk_cred)
1337 gnutls_psk_free_server_credentials (psk_cred);
1338 #endif
1340 #ifdef ENABLE_ANON
1341 gnutls_anon_free_server_credentials (dh_cred);
1342 #endif
1344 if (nodb == 0)
1345 wrap_db_deinit ();
1346 gnutls_global_deinit ();
1348 return 0;
1352 void
1353 gaa_parser (int argc, char **argv)
1355 if (gaa (argc, argv, &info) != -1)
1357 fprintf (stderr,
1358 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1359 exit (1);
1362 disable_client_cert = info.disable_client_cert;
1363 require_cert = info.require_cert;
1364 debug = info.debug;
1365 verbose = info.quiet;
1366 nodb = info.nodb;
1368 if (info.http == 0)
1369 http = 0;
1370 else
1371 http = 1;
1373 if (info.fmtder == 0)
1374 x509ctype = GNUTLS_X509_FMT_PEM;
1375 else
1376 x509ctype = GNUTLS_X509_FMT_DER;
1378 if (info.generate == 0)
1379 generate = 0;
1380 else
1381 generate = 1;
1383 dh_params_file = info.dh_params_file;
1385 port = info.port;
1387 x509_certfile = info.x509_certfile;
1388 x509_keyfile = info.x509_keyfile;
1389 x509_dsacertfile = info.x509_dsacertfile;
1390 x509_dsakeyfile = info.x509_dsakeyfile;
1391 x509_cafile = info.x509_cafile;
1392 x509_crlfile = info.x509_crlfile;
1393 pgp_certfile = info.pgp_certfile;
1394 pgp_keyfile = info.pgp_keyfile;
1395 srp_passwd = info.srp_passwd;
1396 srp_passwd_conf = info.srp_passwd_conf;
1398 psk_passwd = info.psk_passwd;
1400 pgp_keyring = info.pgp_keyring;
1402 parse_protocols (info.proto, info.nproto, protocol_priority);
1403 parse_ciphers (info.ciphers, info.nciphers, cipher_priority);
1404 parse_macs (info.macs, info.nmacs, mac_priority);
1405 parse_ctypes (info.ctype, info.nctype, cert_type_priority);
1406 parse_kx (info.kx, info.nkx, kx_priority);
1407 parse_comp (info.comp, info.ncomp, comp_priority);
1410 void
1411 serv_version (void)
1413 const char *v = gnutls_check_version (NULL);
1415 printf ("gnutls-serv (GnuTLS) %s\n", LIBGNUTLS_VERSION);
1416 if (strcmp (v, LIBGNUTLS_VERSION) != 0)
1417 printf ("libgnutls %s\n", v);
1420 /* session resuming support */
1422 #define SESSION_ID_SIZE 32
1423 #define SESSION_DATA_SIZE 1024
1425 typedef struct
1427 char session_id[SESSION_ID_SIZE];
1428 unsigned int session_id_size;
1430 char session_data[SESSION_DATA_SIZE];
1431 unsigned int session_data_size;
1432 } CACHE;
1434 static CACHE *cache_db;
1435 int cache_db_ptr = 0;
1437 static void
1438 wrap_db_init (void)
1441 /* allocate cache_db */
1442 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1445 static void
1446 wrap_db_deinit (void)
1450 static int
1451 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1454 if (cache_db == NULL)
1455 return -1;
1457 if (key.size > SESSION_ID_SIZE)
1458 return -1;
1459 if (data.size > SESSION_DATA_SIZE)
1460 return -1;
1462 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1463 cache_db[cache_db_ptr].session_id_size = key.size;
1465 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1466 cache_db[cache_db_ptr].session_data_size = data.size;
1468 cache_db_ptr++;
1469 cache_db_ptr %= ssl_session_cache;
1471 return 0;
1474 static gnutls_datum_t
1475 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1477 gnutls_datum_t res = { NULL, 0 };
1478 int i;
1480 if (cache_db == NULL)
1481 return res;
1483 for (i = 0; i < ssl_session_cache; i++)
1485 if (key.size == cache_db[i].session_id_size &&
1486 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1490 res.size = cache_db[i].session_data_size;
1492 res.data = gnutls_malloc (res.size);
1493 if (res.data == NULL)
1494 return res;
1496 memcpy (res.data, cache_db[i].session_data, res.size);
1498 return res;
1501 return res;
1504 static int
1505 wrap_db_delete (void *dbf, gnutls_datum_t key)
1507 int i;
1509 if (cache_db == NULL)
1510 return -1;
1512 for (i = 0; i < ssl_session_cache; i++)
1514 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1515 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1518 cache_db[i].session_id_size = 0;
1519 cache_db[i].session_data_size = 0;
1521 return 0;
1525 return -1;
1529 void
1530 print_serv_license (void)
1532 fputs ("\nCopyright (C) 2001-2003 Paul Sheer, Nikos Mavrogiannopoulos\n"
1533 "\nCopyright (C) 2004 Free Software Foundation\n"
1534 "This program is free software; you can redistribute it and/or modify \n"
1535 "it under the terms of the GNU General Public License as published by \n"
1536 "the Free Software Foundation; either version 3 of the License, or \n"
1537 "(at your option) any later version. \n" "\n"
1538 "This program is distributed in the hope that it will be useful, \n"
1539 "but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
1540 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n"
1541 "GNU General Public License for more details. \n" "\n"
1542 "You should have received a copy of the GNU General Public License \n"
1543 "along with this program; if not, write to the Free Software \n"
1544 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",
1545 stdout);