2 * Copyright (C) 2004, 2006, 2007 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)
31 #include <sys/types.h>
33 #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
;
72 char *x509_dsakeyfile
;
73 char *x509_dsacertfile
;
76 char *x509_crlfile
= NULL
;
80 /* This is a sample TCP echo server.
81 * This will behave as an http server if any argument in the
82 * command line is present
85 #define SMALL_READ_TEST (2147483647)
87 #define SA struct sockaddr
88 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
89 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
93 #define max(x,y) ((x) > (y) ? (x) : (y))
95 #define min(x,y) ((x) < (y) ? (x) : (y))
98 #define HTTP_END "</BODY></HTML>\n\n"
100 #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"
101 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
103 #define HTTP_BEGIN HTTP_OK \
106 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
107 "GNUTLS</a></H1></CENTER>\n\n"
111 /* These are global */
112 gnutls_srp_server_credentials_t srp_cred
= NULL
;
113 gnutls_psk_server_credentials_t psk_cred
= NULL
;
114 gnutls_anon_server_credentials_t dh_cred
= NULL
;
115 gnutls_certificate_credentials_t cert_cred
= NULL
;
119 const int ssl_session_cache
= 128;
121 static void wrap_db_init (void);
122 static void wrap_db_deinit (void);
123 static int wrap_db_store (void *dbf
, gnutls_datum_t key
, gnutls_datum_t data
);
124 static gnutls_datum_t
wrap_db_fetch (void *dbf
, gnutls_datum_t key
);
125 static int wrap_db_delete (void *dbf
, gnutls_datum_t key
);
128 #define HTTP_STATE_REQUEST 1
129 #define HTTP_STATE_RESPONSE 2
130 #define HTTP_STATE_CLOSING 3
132 LIST_TYPE_DECLARE (listener_item
, char *http_request
;
133 char *http_response
; int request_length
;
134 int response_length
; int response_written
;
136 int fd
; gnutls_session_t tls_session
; int handshake_ok
;);
139 safe_strerror (int value
)
141 const char *ret
= gnutls_strerror (value
);
148 listener_free (listener_item
* j
)
152 free (j
->http_request
);
153 if (j
->http_response
)
154 free (j
->http_response
);
157 gnutls_bye (j
->tls_session
, GNUTLS_SHUT_WR
);
160 gnutls_deinit (j
->tls_session
);
165 /* we use primes up to 1024 in this server.
166 * otherwise we should add them here.
169 gnutls_dh_params_t dh_params
= NULL
;
170 gnutls_rsa_params_t rsa_params
= NULL
;
173 generate_dh_primes (void)
175 int prime_bits
= 768;
177 if (gnutls_dh_params_init (&dh_params
) < 0)
179 fprintf (stderr
, "Error in dh parameter initialization\n");
183 /* Generate Diffie Hellman parameters - for use with DHE
184 * kx algorithms. These should be discarded and regenerated
185 * once a week or once a month. Depends on the
186 * security requirements.
189 ("Generating Diffie Hellman parameters [%d]. Please wait...\n",
193 if (gnutls_dh_params_generate2 (dh_params
, prime_bits
) < 0)
195 fprintf (stderr
, "Error in prime generation\n");
203 read_dh_params (void)
207 gnutls_datum_t params
;
210 if (gnutls_dh_params_init (&dh_params
) < 0)
212 fprintf (stderr
, "Error in dh parameter initialization\n");
216 /* read the params file
218 fd
= fopen (dh_params_file
, "r");
221 fprintf (stderr
, "Could not open %s\n", dh_params_file
);
225 size
= fread (tmpdata
, 1, sizeof (tmpdata
) - 1, fd
);
229 params
.data
= (unsigned char *) tmpdata
;
233 gnutls_dh_params_import_pkcs3 (dh_params
, ¶ms
, GNUTLS_X509_FMT_PEM
);
237 fprintf (stderr
, "Error parsing dh params: %s\n", safe_strerror (size
));
241 printf ("Read Diffie Hellman parameters.\n");
246 static char pkcs3
[] =
247 "-----BEGIN DH PARAMETERS-----\n"
248 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
249 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
250 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
251 "-----END DH PARAMETERS-----\n";
254 static_dh_params (void)
256 gnutls_datum_t params
= { pkcs3
, sizeof (pkcs3
) };
259 if (gnutls_dh_params_init (&dh_params
) < 0)
261 fprintf (stderr
, "Error in dh parameter initialization\n");
265 ret
= gnutls_dh_params_import_pkcs3 (dh_params
, ¶ms
, GNUTLS_X509_FMT_PEM
);
269 fprintf (stderr
, "Error parsing dh params: %s\n", safe_strerror (ret
));
273 printf ("Set static Diffie Hellman parameters, consider --dhparams.\n");
279 get_params (gnutls_session_t session
, gnutls_params_type_t type
,
280 gnutls_params_st
* st
)
283 if (type
== GNUTLS_PARAMS_RSA_EXPORT
)
285 if (rsa_params
== NULL
)
287 st
->params
.rsa_export
= rsa_params
;
289 else if (type
== GNUTLS_PARAMS_DH
)
291 if (dh_params
== NULL
)
293 st
->params
.dh
= dh_params
;
305 generate_rsa_params (void)
307 if (gnutls_rsa_params_init (&rsa_params
) < 0)
309 fprintf (stderr
, "Error in rsa parameter initialization\n");
313 /* Generate RSA parameters - for use with RSA-export
314 * cipher suites. These should be discarded and regenerated
315 * once a day, once every 500 transactions etc. Depends on the
316 * security requirements.
318 printf ("Generating temporary RSA parameters. Please wait...\n");
321 if (gnutls_rsa_params_generate2 (rsa_params
, 512) < 0)
323 fprintf (stderr
, "Error in rsa parameter generation\n");
330 LIST_DECLARE_INIT (listener_list
, listener_item
, listener_free
);
332 static int protocol_priority
[PRI_MAX
];
333 static int kx_priority
[PRI_MAX
];
334 static int cipher_priority
[PRI_MAX
];
335 static int comp_priority
[PRI_MAX
];
336 static int mac_priority
[PRI_MAX
];
337 static int cert_type_priority
[PRI_MAX
];
341 oprfi_callback (gnutls_session_t session
,
344 const unsigned char *in_oprfi
,
345 unsigned char *out_oprfi
)
347 size_t ourlen
= strlen (info
.opaque_prf_input
);
350 printf ("- Received Opaque PRF data of %d bytes\n", oprfi_len
);
352 for (i
= 0; i
< oprfi_len
; i
++)
353 printf ("%02x", in_oprfi
[i
]);
356 memset(out_oprfi
, 0, oprfi_len
);
357 strncpy (out_oprfi
, info
.opaque_prf_input
, oprfi_len
);
364 initialize_session (void)
366 gnutls_session_t session
;
369 gnutls_init (&session
, GNUTLS_SERVER
);
371 /* allow the use of private ciphersuites.
373 gnutls_handshake_set_private_extensions (session
, 1);
377 gnutls_db_set_retrieve_function (session
, wrap_db_fetch
);
378 gnutls_db_set_remove_function (session
, wrap_db_delete
);
379 gnutls_db_set_store_function (session
, wrap_db_store
);
380 gnutls_db_set_ptr (session
, NULL
);
383 if (gnutls_priority_set_direct (session
, info
.priorities
, &err
) < 0)
385 fprintf(stderr
, "Syntax error at: %s\n", err
);
389 if (cipher_priority
[0])
390 gnutls_cipher_set_priority (session
, cipher_priority
);
391 if (comp_priority
[0])
392 gnutls_compression_set_priority (session
, comp_priority
);
394 gnutls_kx_set_priority (session
, kx_priority
);
395 if (protocol_priority
[0])
396 gnutls_protocol_set_priority (session
, protocol_priority
);
398 gnutls_mac_set_priority (session
, mac_priority
);
399 if (cert_type_priority
[0])
400 gnutls_certificate_type_set_priority (session
, cert_type_priority
);
402 gnutls_credentials_set (session
, GNUTLS_CRD_ANON
, dh_cred
);
404 if (srp_cred
!= NULL
)
405 gnutls_credentials_set (session
, GNUTLS_CRD_SRP
, srp_cred
);
407 if (psk_cred
!= NULL
)
408 gnutls_credentials_set (session
, GNUTLS_CRD_PSK
, psk_cred
);
410 if (cert_cred
!= NULL
)
411 gnutls_credentials_set (session
, GNUTLS_CRD_CERTIFICATE
, cert_cred
);
413 if (disable_client_cert
)
414 gnutls_certificate_server_set_request (session
, GNUTLS_CERT_IGNORE
);
417 gnutls_certificate_server_set_request (session
, GNUTLS_CERT_REQUIRE
);
419 gnutls_certificate_server_set_request (session
, GNUTLS_CERT_REQUEST
);
422 /* Set maximum compatibility mode. This is only suggested on public webservers
423 * that need to trade security for compatibility
425 gnutls_session_enable_compatibility_mode( session
);
428 if (info
.opaque_prf_input
)
429 gnutls_oprfi_enable_server (session
, oprfi_callback
, NULL
);
435 #include <gnutls/x509.h>
437 static const char DEFAULT_DATA
[] =
438 "This is the default message reported by the GnuTLS implementation. "
439 "For more information please visit "
440 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
442 /* Creates html with the current session information.
444 #define tmp2 &http_buffer[strlen(http_buffer)]
446 peer_print_info (gnutls_session_t session
, int *ret_length
, const char *header
)
449 unsigned char sesid
[32];
450 size_t i
, sesid_size
;
452 gnutls_kx_algorithm_t kx_alg
;
453 size_t len
= 5 * 1024 + strlen (header
);
454 char *crtinfo
= NULL
;
459 http_buffer
= malloc (len
);
460 if (http_buffer
== NULL
)
463 strcpy (http_buffer
, HTTP_BEGIN
);
464 strcpy (&http_buffer
[sizeof (HTTP_BEGIN
) - 1], DEFAULT_DATA
);
465 strcpy (&http_buffer
[sizeof (HTTP_BEGIN
) + sizeof (DEFAULT_DATA
) - 2],
468 sizeof (DEFAULT_DATA
) + sizeof (HTTP_BEGIN
) + sizeof (HTTP_END
) - 3;
473 if (gnutls_certificate_type_get (session
) == GNUTLS_CRT_X509
)
475 const gnutls_datum_t
*cert_list
;
476 unsigned int cert_list_size
= 0;
479 cert_list
= gnutls_certificate_get_peers (session
, &cert_list_size
);
481 for (i
= 0; i
< cert_list_size
; i
++)
483 gnutls_x509_crt_t cert
;
486 if (gnutls_x509_crt_init (&cert
) == 0 &&
487 gnutls_x509_crt_import (cert
, &cert_list
[i
],
488 GNUTLS_X509_FMT_DER
) == 0 &&
489 gnutls_x509_crt_print (cert
, GNUTLS_X509_CRT_FULL
, &info
) == 0)
491 const char *post
= "</PRE><P><PRE>";
493 crtinfo
= realloc (crtinfo
, ncrtinfo
+ info
.size
+
497 memcpy (crtinfo
+ ncrtinfo
, info
.data
, info
.size
);
498 ncrtinfo
+= info
.size
;
499 memcpy (crtinfo
+ ncrtinfo
, post
, strlen (post
));
500 ncrtinfo
+= strlen (post
);
501 crtinfo
[ncrtinfo
] = '\0';
502 gnutls_free (info
.data
);
507 http_buffer
= malloc (len
);
508 if (http_buffer
== NULL
)
511 strcpy (http_buffer
, HTTP_BEGIN
);
513 /* print session_id */
514 gnutls_session_get_id (session
, sesid
, &sesid_size
);
515 sprintf (tmp2
, "\n<p>Session ID: <i>");
516 for (i
= 0; i
< sesid_size
; i
++)
517 sprintf (tmp2
, "%.2X", sesid
[i
]);
518 sprintf (tmp2
, "</i></p>\n");
520 "<h5>If your browser supports session resuming, then you should see the "
521 "same session ID, when you press the <b>reload</b> button.</h5>\n");
523 /* Here unlike print_info() we use the kx algorithm to distinguish
524 * the functions to call.
528 size_t dns_size
= sizeof (dns
);
531 if (gnutls_server_name_get (session
, dns
, &dns_size
, &type
, 0) == 0)
533 sprintf (tmp2
, "\n<p>Server Name: %s</p>\n", dns
);
538 kx_alg
= gnutls_kx_get (session
);
540 /* print srp specific data */
542 if (kx_alg
== GNUTLS_KX_SRP
)
544 sprintf (tmp2
, "<p>Connected as user '%s'.</p>\n",
545 gnutls_srp_server_get_username (session
));
550 if (kx_alg
== GNUTLS_KX_PSK
)
552 sprintf (tmp2
, "<p>Connected as user '%s'.</p>\n",
553 gnutls_psk_server_get_username (session
));
558 if (kx_alg
== GNUTLS_KX_ANON_DH
)
561 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
562 gnutls_dh_get_prime_bits (session
));
566 if (kx_alg
== GNUTLS_KX_DHE_RSA
|| kx_alg
== GNUTLS_KX_DHE_DSS
)
569 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
570 gnutls_dh_get_prime_bits (session
));
573 /* print session information */
574 strcat (http_buffer
, "<P>\n");
576 tmp
= gnutls_protocol_get_name (gnutls_protocol_get_version (session
));
580 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
583 if (gnutls_auth_get_type (session
) == GNUTLS_CRD_CERTIFICATE
)
586 gnutls_certificate_type_get_name (gnutls_certificate_type_get
590 sprintf (tmp2
, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp
);
593 tmp
= gnutls_kx_get_name (kx_alg
);
596 sprintf (tmp2
, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp
);
598 tmp
= gnutls_compression_get_name (gnutls_compression_get (session
));
601 sprintf (tmp2
, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp
);
603 tmp
= gnutls_cipher_get_name (gnutls_cipher_get (session
));
606 sprintf (tmp2
, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp
);
608 tmp
= gnutls_mac_get_name (gnutls_mac_get (session
));
611 sprintf (tmp2
, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp
);
613 tmp
= gnutls_cipher_suite_get_name (kx_alg
,
614 gnutls_cipher_get (session
),
615 gnutls_mac_get (session
));
618 sprintf (tmp2
, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
623 strcat (http_buffer
, "<hr><PRE>");
624 strcat (http_buffer
, crtinfo
);
625 strcat (http_buffer
, "\n</PRE>\n");
628 strcat (http_buffer
, "<hr><P>Your HTTP header was:<PRE>");
629 strcat (http_buffer
, header
);
630 strcat (http_buffer
, "</PRE></P>");
632 strcat (http_buffer
, "\n" HTTP_END
);
634 *ret_length
= strlen (http_buffer
);
640 listen_socket (const char *name
, int listen_port
)
642 struct addrinfo hints
, *res
, *ptr
;
647 snprintf (portname
, sizeof (portname
), "%d", listen_port
);
648 memset (&hints
, 0, sizeof (hints
));
649 hints
.ai_socktype
= SOCK_STREAM
;
650 hints
.ai_flags
= AI_PASSIVE
;
652 if ((s
= getaddrinfo (NULL
, portname
, &hints
, &res
)) != 0)
654 fprintf (stderr
, "getaddrinfo() failed: %s\n", gai_strerror (s
));
659 for (ptr
= res
; (ptr
!= NULL
) && (s
== -1); ptr
= ptr
->ai_next
)
661 if ((s
= socket (ptr
->ai_family
, ptr
->ai_socktype
, ptr
->ai_protocol
)) < 0)
663 perror ("socket() failed");
669 (s
, SOL_SOCKET
, SO_REUSEADDR
, (const void *) &yes
, sizeof (yes
)) < 0)
671 perror ("setsockopt() failed");
678 if (bind (s
, res
->ai_addr
, res
->ai_addrlen
) < 0)
680 perror ("bind() failed");
684 if (listen (s
, 10) < 0)
686 perror ("listen() failed");
697 printf ("%s ready. Listening to port '%s'.\n\n", name
, portname
);
702 get_response (gnutls_session_t session
, char *request
,
703 char **response
, int *response_length
)
709 if (strncmp (request
, "GET ", 4))
712 if (!(h
= strchr (request
, '\n')))
716 while (*h
== '\r' || *h
== '\n')
719 if (!(p
= strchr (request
+ 4, ' ')))
723 /* *response = peer_print_info(session, request+4, h, response_length); */
726 *response
= peer_print_info (session
, response_length
, h
);
730 *response
= strdup (request
);
731 *response_length
= ((*response
) ? strlen (*response
) : 0);
737 *response
= strdup (HTTP_UNIMPLEMENTED
);
738 *response_length
= ((*response
) ? strlen (*response
) : 0);
744 fprintf (stderr
, "Exiting via signal %d\n", sig
);
750 check_alert (gnutls_session_t session
, int ret
)
752 if (ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
753 || ret
== GNUTLS_E_FATAL_ALERT_RECEIVED
)
755 int last_alert
= gnutls_alert_get (session
);
756 if (last_alert
== GNUTLS_A_NO_RENEGOTIATION
&&
757 ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
)
759 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
761 printf ("* Received alert '%d': %s.\n", last_alert
,
762 gnutls_alert_get_name (last_alert
));
767 tls_log_func (int level
, const char *str
)
769 fprintf (stderr
, "|<%d>| %s", level
, str
);
772 static void gaa_parser (int argc
, char **argv
);
774 static int get_port (const struct sockaddr_storage
*addr
)
776 switch (addr
->ss_family
)
779 return ntohs (((const struct sockaddr_in6
*)addr
)->sin6_port
);
781 return ntohs (((const struct sockaddr_in
*)addr
)->sin_port
);
786 static const char *addr_ntop (const struct sockaddr
*sa
, socklen_t salen
,
787 char *buf
, size_t buflen
)
789 if (getnameinfo (sa
, salen
, buf
, buflen
, NULL
, 0, NI_NUMERICHOST
) == 0)
797 main (int argc
, char **argv
)
803 struct sockaddr_storage client_address
;
807 signal (SIGPIPE
, SIG_IGN
);
808 signal (SIGHUP
, SIG_IGN
);
809 signal (SIGTERM
, terminate
);
810 if (signal (SIGINT
, terminate
) == SIG_IGN
)
811 signal (SIGINT
, SIG_IGN
); /* e.g. background process */
816 gaa_parser (argc
, argv
);
823 strcpy (name
, "HTTP Server");
827 strcpy (name
, "Echo Server");
830 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM
, 0);
832 if ((ret
= gnutls_global_init ()) < 0)
834 fprintf (stderr
, "global_init: %s\n", gnutls_strerror (ret
));
837 gnutls_global_set_log_function (tls_log_func
);
838 gnutls_global_set_log_level (debug
);
840 if ((ret
= gnutls_global_init_extra ()) < 0)
842 fprintf (stderr
, "global_init_extra: %s\n", gnutls_strerror (ret
));
846 /* Note that servers must generate parameters for
847 * Diffie Hellman. See gnutls_dh_params_generate(), and
848 * gnutls_dh_params_set().
852 generate_rsa_params ();
853 generate_dh_primes ();
855 else if (dh_params_file
)
864 if (gnutls_certificate_allocate_credentials (&cert_cred
) < 0)
866 fprintf (stderr
, "memory error\n");
870 if (x509_cafile
!= NULL
)
872 if ((ret
= gnutls_certificate_set_x509_trust_file
873 (cert_cred
, x509_cafile
, x509ctype
)) < 0)
875 fprintf (stderr
, "Error reading '%s'\n", x509_cafile
);
881 printf ("Processed %d CA certificate(s).\n", ret
);
885 if (x509_crlfile
!= NULL
)
887 if ((ret
= gnutls_certificate_set_x509_crl_file
888 (cert_cred
, x509_crlfile
, x509ctype
)) < 0)
890 fprintf (stderr
, "Error reading '%s'\n", x509_crlfile
);
896 printf ("Processed %d CRL(s).\n", ret
);
901 #ifdef ENABLE_OPENPGP
902 if (pgp_keyring
!= NULL
)
905 gnutls_certificate_set_openpgp_keyring_file (cert_cred
, pgp_keyring
, GNUTLS_OPENPGP_FMT_BASE64
);
908 fprintf (stderr
, "Error setting the OpenPGP keyring file\n");
913 if (pgp_certfile
!= NULL
)
914 if ((ret
= gnutls_certificate_set_openpgp_key_file
915 (cert_cred
, pgp_certfile
, pgp_keyfile
, GNUTLS_OPENPGP_FMT_BASE64
)) < 0)
918 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
919 ret
, pgp_certfile
, pgp_keyfile
);
924 if (x509_certfile
!= NULL
)
925 if ((ret
= gnutls_certificate_set_x509_key_file
926 (cert_cred
, x509_certfile
, x509_keyfile
, x509ctype
)) < 0)
929 "Error reading '%s' or '%s'\n", x509_certfile
, x509_keyfile
);
934 if (x509_dsacertfile
!= NULL
)
935 if ((ret
= gnutls_certificate_set_x509_key_file
936 (cert_cred
, x509_dsacertfile
, x509_dsakeyfile
, x509ctype
)) < 0)
938 fprintf (stderr
, "Error reading '%s' or '%s'\n",
939 x509_dsacertfile
, x509_dsakeyfile
);
944 gnutls_certificate_set_params_function (cert_cred
, get_params
);
945 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
946 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
949 /* this is a password file (created with the included srpcrypt utility)
950 * Read README.crypt prior to using SRP.
953 if (srp_passwd
!= NULL
)
955 gnutls_srp_allocate_server_credentials (&srp_cred
);
958 gnutls_srp_set_server_credentials_file (srp_cred
, srp_passwd
,
959 srp_passwd_conf
)) < 0)
961 /* only exit is this function is not disabled
963 fprintf (stderr
, "Error while setting SRP parameters\n");
969 /* this is a password file
972 if (psk_passwd
!= NULL
)
974 gnutls_psk_allocate_server_credentials (&psk_cred
);
977 gnutls_psk_set_server_credentials_file (psk_cred
, psk_passwd
)) < 0)
979 /* only exit is this function is not disabled
981 fprintf (stderr
, "Error while setting PSK parameters\n");
985 gnutls_psk_set_server_params_function (psk_cred
, get_params
);
990 gnutls_anon_allocate_server_credentials (&dh_cred
);
991 gnutls_anon_set_server_params_function (dh_cred
, get_params
);
993 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
996 h
= listen_socket (name
, port
);
1010 /* check for new incoming connections */
1014 /* flag which connections we are reading or writing to within the fd sets */
1015 lloopstart (listener_list
, j
)
1019 val
= fcntl (j
->fd
, F_GETFL
, 0);
1020 if ((val
== -1) || (fcntl (j
->fd
, F_SETFL
, val
| O_NONBLOCK
) < 0))
1027 if (j
->http_state
== HTTP_STATE_REQUEST
)
1029 FD_SET (j
->fd
, &rd
);
1032 if (j
->http_state
== HTTP_STATE_RESPONSE
)
1034 FD_SET (j
->fd
, &wr
);
1038 lloopend (listener_list
, j
);
1040 /* core operation */
1041 n
= select (n
+ 1, &rd
, &wr
, NULL
, NULL
);
1042 if (n
== -1 && errno
== EINTR
)
1046 perror ("select()");
1050 /* a new connection has arrived */
1051 if (FD_ISSET (h
, &rd
))
1053 gnutls_session_t tls_session
;
1055 tls_session
= initialize_session ();
1057 calen
= sizeof (client_address
);
1058 memset (&client_address
, 0, calen
);
1059 accept_fd
= accept (h
, (struct sockaddr
*) &client_address
, &calen
);
1063 perror ("accept()");
1070 /* new list entry for the connection */
1071 lappend (listener_list
);
1072 j
= listener_list
.tail
;
1073 j
->http_request
= (char *) strdup ("");
1074 j
->http_state
= HTTP_STATE_REQUEST
;
1077 j
->tls_session
= tls_session
;
1078 gnutls_transport_set_ptr (tls_session
,
1079 (gnutls_transport_ptr_t
) accept_fd
);
1080 j
->handshake_ok
= 0;
1086 ctt
[strlen (ctt
) - 1] = 0;
1089 printf("\n* connection from %s, port %d\n",
1090 inet_ntop(AF_INET, &client_address.sin_addr, topbuf,
1091 sizeof(topbuf)), ntohs(client_address.sin_port));
1098 /* read or write to each connection as indicated by select()'s return argument */
1099 lloopstart (listener_list
, j
)
1101 if (FD_ISSET (j
->fd
, &rd
))
1103 /* read partial GET request */
1107 if (j
->handshake_ok
== 0)
1109 r
= gnutls_handshake (j
->tls_session
);
1110 if (r
< 0 && gnutls_error_is_fatal (r
) == 0)
1112 check_alert (j
->tls_session
, r
);
1115 else if (r
< 0 && gnutls_error_is_fatal (r
) == 1)
1117 check_alert (j
->tls_session
, r
);
1118 fprintf (stderr
, "Error in handshake\n");
1124 gnutls_alert_send_appropriate (j
->tls_session
, r
);
1126 while (ret
== GNUTLS_E_AGAIN
);
1127 j
->http_state
= HTTP_STATE_CLOSING
;
1131 if (gnutls_session_is_resumed (j
->tls_session
) != 0
1133 printf ("*** This is a resumed session\n");
1137 printf ("\n* connection from %s, port %d\n",
1138 addr_ntop ((struct sockaddr
*)&client_address
, calen
,
1139 topbuf
, sizeof (topbuf
)),
1140 get_port (&client_address
));
1141 print_info (j
->tls_session
, NULL
);
1143 j
->handshake_ok
= 1;
1147 if (j
->handshake_ok
== 1)
1149 r
= gnutls_record_recv (j
->tls_session
, buf
,
1150 min (1024, SMALL_READ_TEST
));
1151 if (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
)
1157 j
->http_state
= HTTP_STATE_CLOSING
;
1158 if (r
< 0 && r
!= GNUTLS_E_UNEXPECTED_PACKET_LENGTH
)
1160 check_alert (j
->tls_session
, r
);
1161 fprintf (stderr
, "Error while receiving data\n");
1169 realloc (j
->http_request
, j
->request_length
+ r
+ 1);
1170 if (j
->http_request
!= NULL
)
1172 memcpy (j
->http_request
+ j
->request_length
, buf
, r
);
1173 j
->request_length
+= r
;
1174 j
->http_request
[j
->request_length
] = '\0';
1177 j
->http_state
= HTTP_STATE_CLOSING
;
1180 /* check if we have a full HTTP header */
1182 j
->http_response
= NULL
;
1183 if (j
->http_request
!= NULL
)
1185 if ((http
== 0 && strchr (j
->http_request
, '\n'))
1186 || strstr (j
->http_request
, "\r\n\r\n")
1187 || strstr (j
->http_request
, "\n\n"))
1189 get_response (j
->tls_session
, j
->http_request
,
1190 &j
->http_response
, &j
->response_length
);
1191 j
->http_state
= HTTP_STATE_RESPONSE
;
1192 j
->response_written
= 0;
1197 if (FD_ISSET (j
->fd
, &wr
))
1199 /* write partial response request */
1202 if (j
->handshake_ok
== 0)
1204 r
= gnutls_handshake (j
->tls_session
);
1205 if (r
< 0 && gnutls_error_is_fatal (r
) == 0)
1207 check_alert (j
->tls_session
, r
);
1210 else if (r
< 0 && gnutls_error_is_fatal (r
) == 1)
1214 j
->http_state
= HTTP_STATE_CLOSING
;
1215 check_alert (j
->tls_session
, r
);
1216 fprintf (stderr
, "Error in handshake\n");
1222 gnutls_alert_send_appropriate (j
->tls_session
, r
);
1224 while (ret
== GNUTLS_E_AGAIN
);
1228 if (gnutls_session_is_resumed (j
->tls_session
) != 0
1230 printf ("*** This is a resumed session\n");
1233 printf ("- connection from %s, port %d\n",
1234 addr_ntop ((struct sockaddr
*) &client_address
, calen
,
1235 topbuf
, sizeof (topbuf
)),
1236 get_port (&client_address
));
1238 print_info (j
->tls_session
, NULL
);
1240 j
->handshake_ok
= 1;
1244 if (j
->handshake_ok
== 1)
1246 /* FIXME if j->http_response == NULL? */
1247 r
= gnutls_record_send (j
->tls_session
,
1249 j
->response_written
,
1250 min (j
->response_length
-
1251 j
->response_written
,
1253 if (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
)
1260 j
->http_state
= HTTP_STATE_CLOSING
;
1263 j
->http_state
= HTTP_STATE_REQUEST
;
1264 free (j
->http_response
);
1265 j
->response_length
= 0;
1266 j
->request_length
= 0;
1267 j
->http_request
[0] = 0;
1272 fprintf (stderr
, "Error while sending data\n");
1275 check_alert (j
->tls_session
, r
);
1279 j
->response_written
+= r
;
1280 /* check if we have written a complete response */
1281 if (j
->response_written
== j
->response_length
)
1284 j
->http_state
= HTTP_STATE_CLOSING
;
1287 j
->http_state
= HTTP_STATE_REQUEST
;
1288 free (j
->http_response
);
1289 j
->response_length
= 0;
1290 j
->request_length
= 0;
1291 j
->http_request
[0] = 0;
1298 lloopend (listener_list
, j
);
1300 /* loop through all connections, closing those that are in error */
1301 lloopstart (listener_list
, j
)
1303 if (j
->http_state
== HTTP_STATE_CLOSING
)
1305 ldeleteinc (listener_list
, j
);
1308 lloopend (listener_list
, j
);
1312 gnutls_certificate_free_credentials (cert_cred
);
1316 gnutls_srp_free_server_credentials (srp_cred
);
1321 gnutls_psk_free_server_credentials (psk_cred
);
1325 gnutls_anon_free_server_credentials (dh_cred
);
1330 gnutls_global_deinit ();
1337 gaa_parser (int argc
, char **argv
)
1339 if (gaa (argc
, argv
, &info
) != -1)
1342 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1346 disable_client_cert
= info
.disable_client_cert
;
1347 require_cert
= info
.require_cert
;
1349 verbose
= info
.quiet
;
1357 if (info
.fmtder
== 0)
1358 x509ctype
= GNUTLS_X509_FMT_PEM
;
1360 x509ctype
= GNUTLS_X509_FMT_DER
;
1362 if (info
.generate
== 0)
1367 dh_params_file
= info
.dh_params_file
;
1371 x509_certfile
= info
.x509_certfile
;
1372 x509_keyfile
= info
.x509_keyfile
;
1373 x509_dsacertfile
= info
.x509_dsacertfile
;
1374 x509_dsakeyfile
= info
.x509_dsakeyfile
;
1375 x509_cafile
= info
.x509_cafile
;
1376 x509_crlfile
= info
.x509_crlfile
;
1377 pgp_certfile
= info
.pgp_certfile
;
1378 pgp_keyfile
= info
.pgp_keyfile
;
1379 srp_passwd
= info
.srp_passwd
;
1380 srp_passwd_conf
= info
.srp_passwd_conf
;
1382 psk_passwd
= info
.psk_passwd
;
1384 pgp_keyring
= info
.pgp_keyring
;
1386 parse_protocols (info
.proto
, info
.nproto
, protocol_priority
);
1387 parse_ciphers (info
.ciphers
, info
.nciphers
, cipher_priority
);
1388 parse_macs (info
.macs
, info
.nmacs
, mac_priority
);
1389 parse_ctypes (info
.ctype
, info
.nctype
, cert_type_priority
);
1390 parse_kx (info
.kx
, info
.nkx
, kx_priority
);
1391 parse_comp (info
.comp
, info
.ncomp
, comp_priority
);
1397 const char *v
= gnutls_check_version (NULL
);
1399 printf ("gnutls-serv (GnuTLS) %s\n", LIBGNUTLS_VERSION
);
1400 if (strcmp (v
, LIBGNUTLS_VERSION
) != 0)
1401 printf ("libgnutls %s\n", v
);
1404 /* session resuming support */
1406 #define SESSION_ID_SIZE 32
1407 #define SESSION_DATA_SIZE 1024
1411 char session_id
[SESSION_ID_SIZE
];
1412 unsigned int session_id_size
;
1414 char session_data
[SESSION_DATA_SIZE
];
1415 unsigned int session_data_size
;
1418 static CACHE
*cache_db
;
1419 int cache_db_ptr
= 0;
1425 /* allocate cache_db */
1426 cache_db
= calloc (1, ssl_session_cache
* sizeof (CACHE
));
1430 wrap_db_deinit (void)
1435 wrap_db_store (void *dbf
, gnutls_datum_t key
, gnutls_datum_t data
)
1438 if (cache_db
== NULL
)
1441 if (key
.size
> SESSION_ID_SIZE
)
1443 if (data
.size
> SESSION_DATA_SIZE
)
1446 memcpy (cache_db
[cache_db_ptr
].session_id
, key
.data
, key
.size
);
1447 cache_db
[cache_db_ptr
].session_id_size
= key
.size
;
1449 memcpy (cache_db
[cache_db_ptr
].session_data
, data
.data
, data
.size
);
1450 cache_db
[cache_db_ptr
].session_data_size
= data
.size
;
1453 cache_db_ptr
%= ssl_session_cache
;
1458 static gnutls_datum_t
1459 wrap_db_fetch (void *dbf
, gnutls_datum_t key
)
1461 gnutls_datum_t res
= { NULL
, 0 };
1464 if (cache_db
== NULL
)
1467 for (i
= 0; i
< ssl_session_cache
; i
++)
1469 if (key
.size
== cache_db
[i
].session_id_size
&&
1470 memcmp (key
.data
, cache_db
[i
].session_id
, key
.size
) == 0)
1474 res
.size
= cache_db
[i
].session_data_size
;
1476 res
.data
= gnutls_malloc (res
.size
);
1477 if (res
.data
== NULL
)
1480 memcpy (res
.data
, cache_db
[i
].session_data
, res
.size
);
1489 wrap_db_delete (void *dbf
, gnutls_datum_t key
)
1493 if (cache_db
== NULL
)
1496 for (i
= 0; i
< ssl_session_cache
; i
++)
1498 if (key
.size
== (unsigned int) cache_db
[i
].session_id_size
&&
1499 memcmp (key
.data
, cache_db
[i
].session_id
, key
.size
) == 0)
1502 cache_db
[i
].session_id_size
= 0;
1503 cache_db
[i
].session_data_size
= 0;
1514 print_serv_license (void)
1516 fputs ("\nCopyright (C) 2001-2003 Paul Sheer, Nikos Mavrogiannopoulos\n"
1517 "\nCopyright (C) 2004 Free Software Foundation\n"
1518 "This program is free software; you can redistribute it and/or modify \n"
1519 "it under the terms of the GNU General Public License as published by \n"
1520 "the Free Software Foundation; either version 3 of the License, or \n"
1521 "(at your option) any later version. \n" "\n"
1522 "This program is distributed in the hope that it will be useful, \n"
1523 "but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
1524 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n"
1525 "GNU General Public License for more details. \n" "\n"
1526 "You should have received a copy of the GNU General Public License \n"
1527 "along with this program; if not, write to the Free Software \n"
1528 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",