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)
31 #include <sys/types.h>
33 #include <gnutls/gnutls.h>
35 #include <gnutls/extra.h>
36 #include <gnutls/openpgp.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
48 #include "read-file.h"
50 #include "getaddrinfo.h"
52 /* konqueror cannot handle sending the page in multiple
56 static int generate
= 0;
65 int disable_client_cert
;
69 char *srp_passwd_conf
;
75 char *x509_dsakeyfile
;
76 char *x509_dsacertfile
;
79 char *x509_crlfile
= NULL
;
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))
96 #define max(x,y) ((x) > (y) ? (x) : (y))
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 \
109 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
110 "GNUTLS</a></H1></CENTER>\n\n"
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
;
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
;
139 int fd
; gnutls_session_t tls_session
; int handshake_ok
;);
142 safe_strerror (int value
)
144 const char *ret
= gnutls_strerror (value
);
151 listener_free (listener_item
* j
)
155 free (j
->http_request
);
156 if (j
->http_response
)
157 free (j
->http_response
);
160 gnutls_bye (j
->tls_session
, GNUTLS_SHUT_WR
);
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
;
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");
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.
192 ("Generating Diffie Hellman parameters [%d]. Please wait...\n",
196 if (gnutls_dh_params_generate2 (dh_params
, prime_bits
) < 0)
198 fprintf (stderr
, "Error in prime generation\n");
206 read_dh_params (void)
210 gnutls_datum_t params
;
213 if (gnutls_dh_params_init (&dh_params
) < 0)
215 fprintf (stderr
, "Error in dh parameter initialization\n");
219 /* read the params file
221 fd
= fopen (dh_params_file
, "r");
224 fprintf (stderr
, "Could not open %s\n", dh_params_file
);
228 size
= fread (tmpdata
, 1, sizeof (tmpdata
) - 1, fd
);
232 params
.data
= (unsigned char *) tmpdata
;
236 gnutls_dh_params_import_pkcs3 (dh_params
, ¶ms
, GNUTLS_X509_FMT_PEM
);
240 fprintf (stderr
, "Error parsing dh params: %s\n", safe_strerror (size
));
244 printf ("Read Diffie Hellman parameters.\n");
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";
257 static_dh_params (void)
259 gnutls_datum_t params
= { pkcs3
, sizeof (pkcs3
) };
262 if (gnutls_dh_params_init (&dh_params
) < 0)
264 fprintf (stderr
, "Error in dh parameter initialization\n");
268 ret
= gnutls_dh_params_import_pkcs3 (dh_params
, ¶ms
, GNUTLS_X509_FMT_PEM
);
272 fprintf (stderr
, "Error parsing dh params: %s\n", safe_strerror (ret
));
276 printf ("Set static Diffie Hellman parameters, consider --dhparams.\n");
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
)
290 st
->params
.rsa_export
= rsa_params
;
292 else if (type
== GNUTLS_PARAMS_DH
)
294 if (dh_params
== NULL
)
296 st
->params
.dh
= dh_params
;
308 generate_rsa_params (void)
310 if (gnutls_rsa_params_init (&rsa_params
) < 0)
312 fprintf (stderr
, "Error in rsa parameter initialization\n");
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");
324 if (gnutls_rsa_params_generate2 (rsa_params
, 512) < 0)
326 fprintf (stderr
, "Error in rsa parameter generation\n");
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
];
344 oprfi_callback (gnutls_session_t session
,
347 const unsigned char *in_oprfi
,
348 unsigned char *out_oprfi
)
350 size_t ourlen
= strlen (info
.opaque_prf_input
);
353 printf ("- Received Opaque PRF data of %d bytes\n", oprfi_len
);
355 for (i
= 0; i
< oprfi_len
; i
++)
356 printf ("%02x", in_oprfi
[i
]);
359 memset(out_oprfi
, 0, oprfi_len
);
360 strncpy (out_oprfi
, info
.opaque_prf_input
, oprfi_len
);
367 initialize_session (void)
369 gnutls_session_t session
;
372 gnutls_init (&session
, GNUTLS_SERVER
);
374 /* allow the use of private ciphersuites.
376 gnutls_handshake_set_private_extensions (session
, 1);
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
);
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
);
397 gnutls_kx_set_priority (session
, kx_priority
);
398 if (protocol_priority
[0])
399 gnutls_protocol_set_priority (session
, protocol_priority
);
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
);
420 gnutls_certificate_server_set_request (session
, GNUTLS_CERT_REQUIRE
);
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
);
431 if (info
.opaque_prf_input
)
432 gnutls_oprfi_enable_server (session
, oprfi_callback
, NULL
);
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)]
449 peer_print_info (gnutls_session_t session
, int *ret_length
, const char *header
)
452 unsigned char sesid
[32];
453 size_t i
, sesid_size
;
455 gnutls_kx_algorithm_t kx_alg
;
456 size_t len
= 5 * 1024 + strlen (header
);
457 char *crtinfo
= NULL
;
462 http_buffer
= malloc (len
);
463 if (http_buffer
== 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],
471 sizeof (DEFAULT_DATA
) + sizeof (HTTP_BEGIN
) + sizeof (HTTP_END
) - 3;
476 if (gnutls_certificate_type_get (session
) == GNUTLS_CRT_X509
)
478 const gnutls_datum_t
*cert_list
;
479 unsigned int cert_list_size
= 0;
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
;
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
+
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
)
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");
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.
531 size_t dns_size
= sizeof (dns
);
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 */
545 if (kx_alg
== GNUTLS_KX_SRP
)
547 sprintf (tmp2
, "<p>Connected as user '%s'.</p>\n",
548 gnutls_srp_server_get_username (session
));
553 if (kx_alg
== GNUTLS_KX_PSK
)
555 sprintf (tmp2
, "<p>Connected as user '%s'.</p>\n",
556 gnutls_psk_server_get_username (session
));
561 if (kx_alg
== GNUTLS_KX_ANON_DH
)
564 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
565 gnutls_dh_get_prime_bits (session
));
569 if (kx_alg
== GNUTLS_KX_DHE_RSA
|| kx_alg
== GNUTLS_KX_DHE_DSS
)
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
));
583 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
586 if (gnutls_auth_get_type (session
) == GNUTLS_CRD_CERTIFICATE
)
589 gnutls_certificate_type_get_name (gnutls_certificate_type_get
593 sprintf (tmp2
, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp
);
596 tmp
= gnutls_kx_get_name (kx_alg
);
599 sprintf (tmp2
, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp
);
601 tmp
= gnutls_compression_get_name (gnutls_compression_get (session
));
604 sprintf (tmp2
, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp
);
606 tmp
= gnutls_cipher_get_name (gnutls_cipher_get (session
));
609 sprintf (tmp2
, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp
);
611 tmp
= gnutls_mac_get_name (gnutls_mac_get (session
));
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
));
621 sprintf (tmp2
, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
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
);
643 listen_socket (const char *name
, int listen_port
)
645 struct addrinfo hints
, *res
, *ptr
;
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
));
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");
672 (s
, SOL_SOCKET
, SO_REUSEADDR
, (const void *) &yes
, sizeof (yes
)) < 0)
674 perror ("setsockopt() failed");
681 if (bind (s
, res
->ai_addr
, res
->ai_addrlen
) < 0)
683 perror ("bind() failed");
687 if (listen (s
, 10) < 0)
689 perror ("listen() failed");
700 printf ("%s ready. Listening to port '%s'.\n\n", name
, portname
);
705 get_response (gnutls_session_t session
, char *request
,
706 char **response
, int *response_length
)
712 if (strncmp (request
, "GET ", 4))
715 if (!(h
= strchr (request
, '\n')))
719 while (*h
== '\r' || *h
== '\n')
722 if (!(p
= strchr (request
+ 4, ' ')))
726 /* *response = peer_print_info(session, request+4, h, response_length); */
729 *response
= peer_print_info (session
, response_length
, h
);
733 *response
= strdup (request
);
734 *response_length
= ((*response
) ? strlen (*response
) : 0);
740 *response
= strdup (HTTP_UNIMPLEMENTED
);
741 *response_length
= ((*response
) ? strlen (*response
) : 0);
747 fprintf (stderr
, "Exiting via signal %d\n", sig
);
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
)
762 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
764 printf ("* Received alert '%d': %s.\n", last_alert
,
765 gnutls_alert_get_name (last_alert
));
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
)
782 return ntohs (((const struct sockaddr_in6
*)addr
)->sin6_port
);
784 return ntohs (((const struct sockaddr_in
*)addr
)->sin_port
);
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)
800 main (int argc
, char **argv
)
806 struct sockaddr_storage client_address
;
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 */
819 gaa_parser (argc
, argv
);
826 strcpy (name
, "HTTP Server");
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
));
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().
849 generate_rsa_params ();
850 generate_dh_primes ();
852 else if (dh_params_file
)
861 if (gnutls_certificate_allocate_credentials (&cert_cred
) < 0)
863 fprintf (stderr
, "memory error\n");
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
);
878 printf ("Processed %d CA certificate(s).\n", ret
);
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
);
893 printf ("Processed %d CRL(s).\n", ret
);
898 #ifdef ENABLE_OPENPGP
899 if (pgp_keyring
!= NULL
)
902 gnutls_certificate_set_openpgp_keyring_file (cert_cred
, pgp_keyring
, GNUTLS_OPENPGP_FMT_BASE64
);
905 fprintf (stderr
, "Error setting the OpenPGP keyring file\n");
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
);
916 ret
= gnutls_certificate_set_openpgp_key_file
917 (cert_cred
, pgp_certfile
, pgp_keyfile
, GNUTLS_OPENPGP_FMT_BASE64
);
922 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
923 ret
, pgp_certfile
, pgp_keyfile
);
929 if (x509_certfile
!= NULL
)
930 if ((ret
= gnutls_certificate_set_x509_key_file
931 (cert_cred
, x509_certfile
, x509_keyfile
, x509ctype
)) < 0)
934 "Error reading '%s' or '%s'\n", x509_certfile
, x509_keyfile
);
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
);
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.
958 if (srp_passwd
!= NULL
)
960 gnutls_srp_allocate_server_credentials (&srp_cred
);
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");
974 /* this is a password file
977 if (psk_passwd
!= NULL
)
979 gnutls_psk_allocate_server_credentials (&psk_cred
);
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");
992 ret
= gnutls_psk_set_server_credentials_hint (psk_cred
,
996 fprintf (stderr
, "Error setting PSK identity hint.\n");
1001 gnutls_psk_set_server_params_function (psk_cred
, get_params
);
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); */
1012 h
= listen_socket (name
, port
);
1026 /* check for new incoming connections */
1030 /* flag which connections we are reading or writing to within the fd sets */
1031 lloopstart (listener_list
, j
)
1035 val
= fcntl (j
->fd
, F_GETFL
, 0);
1036 if ((val
== -1) || (fcntl (j
->fd
, F_SETFL
, val
| O_NONBLOCK
) < 0))
1043 if (j
->http_state
== HTTP_STATE_REQUEST
)
1045 FD_SET (j
->fd
, &rd
);
1048 if (j
->http_state
== HTTP_STATE_RESPONSE
)
1050 FD_SET (j
->fd
, &wr
);
1054 lloopend (listener_list
, j
);
1056 /* core operation */
1057 n
= select (n
+ 1, &rd
, &wr
, NULL
, NULL
);
1058 if (n
== -1 && errno
== EINTR
)
1062 perror ("select()");
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
);
1079 perror ("accept()");
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
;
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;
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 */
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
);
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");
1140 gnutls_alert_send_appropriate (j
->tls_session
, r
);
1142 while (ret
== GNUTLS_E_AGAIN
);
1143 j
->http_state
= HTTP_STATE_CLOSING
;
1147 if (gnutls_session_is_resumed (j
->tls_session
) != 0
1149 printf ("*** This is a resumed session\n");
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
)
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");
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';
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 */
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
);
1226 else if (r
< 0 && gnutls_error_is_fatal (r
) == 1)
1230 j
->http_state
= HTTP_STATE_CLOSING
;
1231 check_alert (j
->tls_session
, r
);
1232 fprintf (stderr
, "Error in handshake\n");
1238 gnutls_alert_send_appropriate (j
->tls_session
, r
);
1240 while (ret
== GNUTLS_E_AGAIN
);
1244 if (gnutls_session_is_resumed (j
->tls_session
) != 0
1246 printf ("*** This is a resumed session\n");
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
,
1265 j
->response_written
,
1266 min (j
->response_length
-
1267 j
->response_written
,
1269 if (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
)
1276 j
->http_state
= HTTP_STATE_CLOSING
;
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;
1288 fprintf (stderr
, "Error while sending data\n");
1291 check_alert (j
->tls_session
, r
);
1295 j
->response_written
+= r
;
1296 /* check if we have written a complete response */
1297 if (j
->response_written
== j
->response_length
)
1300 j
->http_state
= HTTP_STATE_CLOSING
;
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
);
1332 gnutls_srp_free_server_credentials (srp_cred
);
1337 gnutls_psk_free_server_credentials (psk_cred
);
1341 gnutls_anon_free_server_credentials (dh_cred
);
1346 gnutls_global_deinit ();
1353 gaa_parser (int argc
, char **argv
)
1355 if (gaa (argc
, argv
, &info
) != -1)
1358 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1362 disable_client_cert
= info
.disable_client_cert
;
1363 require_cert
= info
.require_cert
;
1365 verbose
= info
.quiet
;
1373 if (info
.fmtder
== 0)
1374 x509ctype
= GNUTLS_X509_FMT_PEM
;
1376 x509ctype
= GNUTLS_X509_FMT_DER
;
1378 if (info
.generate
== 0)
1383 dh_params_file
= info
.dh_params_file
;
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
);
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
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
;
1434 static CACHE
*cache_db
;
1435 int cache_db_ptr
= 0;
1441 /* allocate cache_db */
1442 cache_db
= calloc (1, ssl_session_cache
* sizeof (CACHE
));
1446 wrap_db_deinit (void)
1451 wrap_db_store (void *dbf
, gnutls_datum_t key
, gnutls_datum_t data
)
1454 if (cache_db
== NULL
)
1457 if (key
.size
> SESSION_ID_SIZE
)
1459 if (data
.size
> SESSION_DATA_SIZE
)
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
;
1469 cache_db_ptr
%= ssl_session_cache
;
1474 static gnutls_datum_t
1475 wrap_db_fetch (void *dbf
, gnutls_datum_t key
)
1477 gnutls_datum_t res
= { NULL
, 0 };
1480 if (cache_db
== NULL
)
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
)
1496 memcpy (res
.data
, cache_db
[i
].session_data
, res
.size
);
1505 wrap_db_delete (void *dbf
, gnutls_datum_t key
)
1509 if (cache_db
== NULL
)
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;
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",