2 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 Free Software
4 * Copyright (C) 2001,2002 Paul Sheer
5 * Portions Copyright (C) 2002,2003 Nikos Mavrogiannopoulos
7 * This file is part of GNUTLS.
9 * GNUTLS is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * GNUTLS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* This server is heavily modified for GNUTLS by Nikos Mavrogiannopoulos
24 * (which means it is quite unreadable)
34 #include <sys/types.h>
36 #include <gnutls/gnutls.h>
38 #include <gnutls/extra.h>
39 #include <gnutls/openpgp.h>
41 #include <sys/select.h>
47 /* Gnulib portability files. */
49 #include "version-etc.h"
50 #include "read-file.h"
54 /* konqueror cannot handle sending the page in multiple
58 static int generate
= 0;
68 int disable_client_cert
;
72 char *srp_passwd_conf
;
78 char *x509_dsakeyfile
;
79 char *x509_dsacertfile
;
82 char *x509_crlfile
= NULL
;
84 gnutls_datum_t session_ticket_key
;
88 /* This is a sample TCP echo server.
89 * This will behave as an http server if any argument in the
90 * command line is present
93 #define SMALL_READ_TEST (2147483647)
95 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
97 #define HTTP_END "</BODY></HTML>\n\n"
99 #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"
100 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
102 #define HTTP_BEGIN HTTP_OK \
105 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
106 "GNUTLS</a></H1></CENTER>\n\n"
108 /* These are global */
109 gnutls_srp_server_credentials_t srp_cred
= NULL
;
110 gnutls_psk_server_credentials_t psk_cred
= NULL
;
111 gnutls_anon_server_credentials_t dh_cred
= NULL
;
112 gnutls_certificate_credentials_t cert_cred
= NULL
;
116 const int ssl_session_cache
= 128;
118 static void wrap_db_init (void);
119 static void wrap_db_deinit (void);
120 static int wrap_db_store (void *dbf
, gnutls_datum_t key
, gnutls_datum_t data
);
121 static gnutls_datum_t
wrap_db_fetch (void *dbf
, gnutls_datum_t key
);
122 static int wrap_db_delete (void *dbf
, gnutls_datum_t key
);
125 #define HTTP_STATE_REQUEST 1
126 #define HTTP_STATE_RESPONSE 2
127 #define HTTP_STATE_CLOSING 3
129 LIST_TYPE_DECLARE (listener_item
, char *http_request
;
130 char *http_response
; int request_length
;
131 int response_length
; int response_written
;
132 int http_state
; int listen_socket
;
133 int fd
; gnutls_session_t tls_session
; int handshake_ok
;);
136 safe_strerror (int value
)
138 const char *ret
= gnutls_strerror (value
);
145 listener_free (listener_item
* j
)
148 free (j
->http_request
);
149 free (j
->http_response
);
152 gnutls_bye (j
->tls_session
, GNUTLS_SHUT_WR
);
155 gnutls_deinit (j
->tls_session
);
160 /* we use primes up to 1024 in this server.
161 * otherwise we should add them here.
164 gnutls_dh_params_t dh_params
= NULL
;
165 gnutls_rsa_params_t rsa_params
= NULL
;
168 generate_dh_primes (void)
170 int prime_bits
= 768;
172 if (gnutls_dh_params_init (&dh_params
) < 0)
174 fprintf (stderr
, "Error in dh parameter initialization\n");
178 /* Generate Diffie-Hellman parameters - for use with DHE
179 * kx algorithms. These should be discarded and regenerated
180 * once a week or once a month. Depends on the
181 * security requirements.
184 ("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
188 if (gnutls_dh_params_generate2 (dh_params
, prime_bits
) < 0)
190 fprintf (stderr
, "Error in prime generation\n");
198 read_dh_params (void)
202 gnutls_datum_t params
;
205 if (gnutls_dh_params_init (&dh_params
) < 0)
207 fprintf (stderr
, "Error in dh parameter initialization\n");
211 /* read the params file
213 fd
= fopen (dh_params_file
, "r");
216 fprintf (stderr
, "Could not open %s\n", dh_params_file
);
220 size
= fread (tmpdata
, 1, sizeof (tmpdata
) - 1, fd
);
224 params
.data
= (unsigned char *) tmpdata
;
228 gnutls_dh_params_import_pkcs3 (dh_params
, ¶ms
, GNUTLS_X509_FMT_PEM
);
232 fprintf (stderr
, "Error parsing dh params: %s\n", safe_strerror (size
));
236 printf ("Read Diffie-Hellman parameters.\n");
241 static char pkcs3
[] =
242 "-----BEGIN DH PARAMETERS-----\n"
243 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
244 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
245 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
246 "-----END DH PARAMETERS-----\n";
249 static_dh_params (void)
251 gnutls_datum_t params
= { pkcs3
, sizeof (pkcs3
) };
254 if (gnutls_dh_params_init (&dh_params
) < 0)
256 fprintf (stderr
, "Error in dh parameter initialization\n");
260 ret
= gnutls_dh_params_import_pkcs3 (dh_params
, ¶ms
,
261 GNUTLS_X509_FMT_PEM
);
265 fprintf (stderr
, "Error parsing dh params: %s\n", safe_strerror (ret
));
269 printf ("Set static Diffie-Hellman parameters, consider --dhparams.\n");
275 get_params (gnutls_session_t session
, gnutls_params_type_t type
,
276 gnutls_params_st
* st
)
279 if (type
== GNUTLS_PARAMS_RSA_EXPORT
)
281 if (rsa_params
== NULL
)
283 st
->params
.rsa_export
= rsa_params
;
285 else if (type
== GNUTLS_PARAMS_DH
)
287 if (dh_params
== NULL
)
289 st
->params
.dh
= dh_params
;
301 generate_rsa_params (void)
303 if (gnutls_rsa_params_init (&rsa_params
) < 0)
305 fprintf (stderr
, "Error in rsa parameter initialization\n");
309 /* Generate RSA parameters - for use with RSA-export
310 * cipher suites. These should be discarded and regenerated
311 * once a day, once every 500 transactions etc. Depends on the
312 * security requirements.
314 printf ("Generating temporary RSA parameters. Please wait...\n");
317 if (gnutls_rsa_params_generate2 (rsa_params
, 512) < 0)
319 fprintf (stderr
, "Error in rsa parameter generation\n");
326 LIST_DECLARE_INIT (listener_list
, listener_item
, listener_free
);
328 static int protocol_priority
[PRI_MAX
];
329 static int kx_priority
[PRI_MAX
];
330 static int cipher_priority
[PRI_MAX
];
331 static int comp_priority
[PRI_MAX
];
332 static int mac_priority
[PRI_MAX
];
333 static int cert_type_priority
[PRI_MAX
];
337 oprfi_callback (gnutls_session_t session
,
340 const unsigned char *in_oprfi
, unsigned char *out_oprfi
)
342 size_t ourlen
= strlen (info
.opaque_prf_input
);
345 printf ("- Received Opaque PRF data of %d bytes\n", oprfi_len
);
347 for (i
= 0; i
< oprfi_len
; i
++)
348 printf ("%02x", in_oprfi
[i
]);
351 memset (out_oprfi
, 0, oprfi_len
);
352 strncpy (out_oprfi
, info
.opaque_prf_input
, oprfi_len
);
358 static gnutls_session_t
359 initialize_session (void)
361 gnutls_session_t session
;
364 gnutls_init (&session
, GNUTLS_SERVER
);
366 /* allow the use of private ciphersuites.
368 gnutls_handshake_set_private_extensions (session
, 1);
372 gnutls_db_set_retrieve_function (session
, wrap_db_fetch
);
373 gnutls_db_set_remove_function (session
, wrap_db_delete
);
374 gnutls_db_set_store_function (session
, wrap_db_store
);
375 gnutls_db_set_ptr (session
, NULL
);
377 #ifdef ENABLE_SESSION_TICKET
379 gnutls_session_ticket_enable_server (session
, &session_ticket_key
);
382 if (gnutls_priority_set_direct (session
, info
.priorities
, &err
) < 0)
384 fprintf (stderr
, "Syntax error at: %s\n", err
);
388 if (cipher_priority
[0])
389 gnutls_cipher_set_priority (session
, cipher_priority
);
390 if (comp_priority
[0])
391 gnutls_compression_set_priority (session
, comp_priority
);
393 gnutls_kx_set_priority (session
, kx_priority
);
394 if (protocol_priority
[0])
395 gnutls_protocol_set_priority (session
, protocol_priority
);
397 gnutls_mac_set_priority (session
, mac_priority
);
398 if (cert_type_priority
[0])
399 gnutls_certificate_type_set_priority (session
, cert_type_priority
);
401 gnutls_credentials_set (session
, GNUTLS_CRD_ANON
, dh_cred
);
403 if (srp_cred
!= NULL
)
404 gnutls_credentials_set (session
, GNUTLS_CRD_SRP
, srp_cred
);
406 if (psk_cred
!= NULL
)
407 gnutls_credentials_set (session
, GNUTLS_CRD_PSK
, psk_cred
);
409 if (cert_cred
!= NULL
)
410 gnutls_credentials_set (session
, GNUTLS_CRD_CERTIFICATE
, cert_cred
);
412 if (disable_client_cert
)
413 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
);
423 if (info
.opaque_prf_input
)
424 gnutls_oprfi_enable_server (session
, oprfi_callback
, NULL
);
430 #include <gnutls/x509.h>
432 static const char DEFAULT_DATA
[] =
433 "This is the default message reported by the GnuTLS implementation. "
434 "For more information please visit "
435 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
437 /* Creates html with the current session information.
439 #define tmp2 &http_buffer[strlen(http_buffer)]
441 peer_print_info (gnutls_session_t session
, int *ret_length
,
445 unsigned char sesid
[32];
446 size_t i
, sesid_size
;
448 gnutls_kx_algorithm_t kx_alg
;
449 size_t len
= 5 * 1024 + strlen (header
);
450 char *crtinfo
= NULL
;
455 http_buffer
= malloc (len
);
456 if (http_buffer
== NULL
)
459 strcpy (http_buffer
, HTTP_BEGIN
);
460 strcpy (&http_buffer
[sizeof (HTTP_BEGIN
) - 1], DEFAULT_DATA
);
461 strcpy (&http_buffer
[sizeof (HTTP_BEGIN
) + sizeof (DEFAULT_DATA
) - 2],
464 sizeof (DEFAULT_DATA
) + sizeof (HTTP_BEGIN
) + sizeof (HTTP_END
) - 3;
469 if (gnutls_certificate_type_get (session
) == GNUTLS_CRT_X509
)
471 const gnutls_datum_t
*cert_list
;
472 unsigned int cert_list_size
= 0;
474 cert_list
= gnutls_certificate_get_peers (session
, &cert_list_size
);
476 for (i
= 0; i
< cert_list_size
; i
++)
478 gnutls_x509_crt_t cert
;
481 if (gnutls_x509_crt_init (&cert
) == 0 &&
482 gnutls_x509_crt_import (cert
, &cert_list
[i
],
483 GNUTLS_X509_FMT_DER
) == 0 &&
484 gnutls_x509_crt_print (cert
, GNUTLS_CRT_PRINT_FULL
, &info
) == 0)
486 const char *post
= "</PRE><P><PRE>";
488 crtinfo
= realloc (crtinfo
, ncrtinfo
+ info
.size
+
492 memcpy (crtinfo
+ ncrtinfo
, info
.data
, info
.size
);
493 ncrtinfo
+= info
.size
;
494 memcpy (crtinfo
+ ncrtinfo
, post
, strlen (post
));
495 ncrtinfo
+= strlen (post
);
496 crtinfo
[ncrtinfo
] = '\0';
497 gnutls_free (info
.data
);
502 http_buffer
= malloc (len
);
503 if (http_buffer
== NULL
)
509 strcpy (http_buffer
, HTTP_BEGIN
);
511 /* print session_id */
512 gnutls_session_get_id (session
, sesid
, &sesid_size
);
513 sprintf (tmp2
, "\n<p>Session ID: <i>");
514 for (i
= 0; i
< sesid_size
; i
++)
515 sprintf (tmp2
, "%.2X", sesid
[i
]);
516 sprintf (tmp2
, "</i></p>\n");
518 "<h5>If your browser supports session resuming, then you should see the "
519 "same session ID, when you press the <b>reload</b> button.</h5>\n");
521 /* Here unlike print_info() we use the kx algorithm to distinguish
522 * the functions to call.
526 size_t dns_size
= sizeof (dns
);
529 if (gnutls_server_name_get (session
, dns
, &dns_size
, &type
, 0) == 0)
531 sprintf (tmp2
, "\n<p>Server Name: %s</p>\n", dns
);
536 kx_alg
= gnutls_kx_get (session
);
538 /* print srp specific data */
540 if (kx_alg
== GNUTLS_KX_SRP
)
542 sprintf (tmp2
, "<p>Connected as user '%s'.</p>\n",
543 gnutls_srp_server_get_username (session
));
548 if (kx_alg
== GNUTLS_KX_PSK
)
550 sprintf (tmp2
, "<p>Connected as user '%s'.</p>\n",
551 gnutls_psk_server_get_username (session
));
556 if (kx_alg
== GNUTLS_KX_ANON_DH
)
559 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
560 gnutls_dh_get_prime_bits (session
));
564 if (kx_alg
== GNUTLS_KX_DHE_RSA
|| kx_alg
== GNUTLS_KX_DHE_DSS
)
567 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
568 gnutls_dh_get_prime_bits (session
));
571 /* print session information */
572 strcat (http_buffer
, "<P>\n");
574 tmp
= gnutls_protocol_get_name (gnutls_protocol_get_version (session
));
578 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
581 if (gnutls_auth_get_type (session
) == GNUTLS_CRD_CERTIFICATE
)
584 gnutls_certificate_type_get_name (gnutls_certificate_type_get
588 sprintf (tmp2
, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp
);
591 tmp
= gnutls_kx_get_name (kx_alg
);
594 sprintf (tmp2
, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp
);
596 tmp
= gnutls_compression_get_name (gnutls_compression_get (session
));
599 sprintf (tmp2
, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp
);
601 tmp
= gnutls_cipher_get_name (gnutls_cipher_get (session
));
604 sprintf (tmp2
, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp
);
606 tmp
= gnutls_mac_get_name (gnutls_mac_get (session
));
609 sprintf (tmp2
, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp
);
611 tmp
= gnutls_cipher_suite_get_name (kx_alg
,
612 gnutls_cipher_get (session
),
613 gnutls_mac_get (session
));
616 sprintf (tmp2
, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
621 strcat (http_buffer
, "<hr><PRE>");
622 strcat (http_buffer
, crtinfo
);
623 strcat (http_buffer
, "\n</PRE>\n");
627 strcat (http_buffer
, "<hr><P>Your HTTP header was:<PRE>");
628 strcat (http_buffer
, header
);
629 strcat (http_buffer
, "</PRE></P>");
631 strcat (http_buffer
, "\n" HTTP_END
);
633 *ret_length
= strlen (http_buffer
);
639 human_addr (const struct sockaddr
*sa
, socklen_t salen
,
640 char *buf
, size_t buflen
)
642 const char *save_buf
= buf
;
650 switch (sa
->sa_family
)
654 snprintf (buf
, buflen
, "IPv6 ");
659 snprintf (buf
, buflen
, "IPv4 ");
667 if (getnameinfo (sa
, salen
, buf
, buflen
, NULL
, 0, NI_NUMERICHOST
) != 0)
674 strncat (buf
, " port ", buflen
);
680 if (getnameinfo (sa
, salen
, NULL
, 0, buf
, buflen
, NI_NUMERICSERV
) != 0)
687 listen_socket (const char *name
, int listen_port
)
689 struct addrinfo hints
, *res
, *ptr
;
693 listener_item
*j
= NULL
;
695 snprintf (portname
, sizeof (portname
), "%d", listen_port
);
696 memset (&hints
, 0, sizeof (hints
));
697 hints
.ai_socktype
= SOCK_STREAM
;
698 hints
.ai_flags
= AI_PASSIVE
;
700 if ((s
= getaddrinfo (NULL
, portname
, &hints
, &res
)) != 0)
702 fprintf (stderr
, "getaddrinfo() failed: %s\n", gai_strerror (s
));
706 for (ptr
= res
; ptr
!= NULL
; ptr
= ptr
->ai_next
)
708 /* Print what we are doing. */
712 fprintf (stderr
, "%s listening on %s...",
713 name
, human_addr (ptr
->ai_addr
, ptr
->ai_addrlen
,
714 topbuf
, sizeof (topbuf
)));
717 if ((s
= socket (ptr
->ai_family
, ptr
->ai_socktype
,
718 ptr
->ai_protocol
)) < 0)
720 perror ("socket() failed");
725 if (setsockopt (s
, SOL_SOCKET
, SO_REUSEADDR
,
726 (const void *) &yes
, sizeof (yes
)) < 0)
728 perror ("setsockopt() failed");
734 if (bind (s
, ptr
->ai_addr
, ptr
->ai_addrlen
) < 0)
736 perror ("bind() failed");
740 if (listen (s
, 10) < 0)
742 perror ("listen() failed");
746 /* new list entry for the connection */
747 lappend (listener_list
);
748 j
= listener_list
.tail
;
749 j
->listen_socket
= 1;
752 /* Complete earlier message. */
753 fprintf (stderr
, "done\n");
766 get_response (gnutls_session_t session
, char *request
,
767 char **response
, int *response_length
)
773 if (strncmp (request
, "GET ", 4))
776 if (!(h
= strchr (request
, '\n')))
780 while (*h
== '\r' || *h
== '\n')
783 if (!(p
= strchr (request
+ 4, ' ')))
787 /* *response = peer_print_info(session, request+4, h, response_length); */
790 *response
= peer_print_info (session
, response_length
, h
);
794 fprintf(stderr
, "received: %s\n", request
);
795 if (request
[0] == request
[1] && request
[0] == '*')
797 if (strncmp(request
, "**REHANDSHAKE**", sizeof("**REHANDSHAKE**")-1)==0)
799 fprintf(stderr
, "*** Sending rehandshake request\n");
800 gnutls_rehandshake(session
);
803 *response_length
= 0;
806 *response
= strdup (request
);
807 *response_length
= ((*response
) ? strlen (*response
) : 0);
813 *response
= strdup (HTTP_UNIMPLEMENTED
);
814 *response_length
= ((*response
) ? strlen (*response
) : 0);
817 static void terminate (int sig
) __attribute__ ((noreturn
));
822 fprintf (stderr
, "Exiting via signal %d\n", sig
);
828 check_alert (gnutls_session_t session
, int ret
)
830 if (ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
831 || ret
== GNUTLS_E_FATAL_ALERT_RECEIVED
)
833 int last_alert
= gnutls_alert_get (session
);
834 if (last_alert
== GNUTLS_A_NO_RENEGOTIATION
&&
835 ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
)
837 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
839 printf ("* Received alert '%d': %s.\n", last_alert
,
840 gnutls_alert_get_name (last_alert
));
845 tls_log_func (int level
, const char *str
)
847 fprintf (stderr
, "|<%d>| %s", level
, str
);
850 static void gaa_parser (int argc
, char **argv
);
853 main (int argc
, char **argv
)
859 struct sockaddr_storage client_address
;
862 set_program_name (argv
[0]);
864 #ifdef gcry_fips_mode_active
865 /* Libgcrypt manual says that gcry_version_check must be called
866 before calling gcry_fips_mode_active. */
867 gcry_check_version (NULL
);
868 if (gcry_fips_mode_active ())
870 ret
= gnutls_register_md5_handler ();
872 fprintf (stderr
, "gnutls_register_md5_handler: %s\n",
873 gnutls_strerror (ret
));
878 signal (SIGPIPE
, SIG_IGN
);
879 signal (SIGHUP
, SIG_IGN
);
880 signal (SIGTERM
, terminate
);
881 if (signal (SIGINT
, terminate
) == SIG_IGN
)
882 signal (SIGINT
, SIG_IGN
); /* e.g. background process */
887 gaa_parser (argc
, argv
);
894 strcpy (name
, "HTTP Server");
898 strcpy (name
, "Echo Server");
901 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM
, 0);
903 if ((ret
= gnutls_global_init ()) < 0)
905 fprintf (stderr
, "global_init: %s\n", gnutls_strerror (ret
));
909 if ((ret
= gnutls_global_init_extra ()) < 0)
911 fprintf (stderr
, "global_init_extra: %s\n", gnutls_strerror (ret
));
915 gnutls_global_set_log_function (tls_log_func
);
916 gnutls_global_set_log_level (debug
);
918 /* Note that servers must generate parameters for
919 * Diffie-Hellman. See gnutls_dh_params_generate(), and
920 * gnutls_dh_params_set().
924 generate_rsa_params ();
925 generate_dh_primes ();
927 else if (dh_params_file
)
936 if (gnutls_certificate_allocate_credentials (&cert_cred
) < 0)
938 fprintf (stderr
, "memory error\n");
942 if (x509_cafile
!= NULL
)
944 if ((ret
= gnutls_certificate_set_x509_trust_file
945 (cert_cred
, x509_cafile
, x509ctype
)) < 0)
947 fprintf (stderr
, "Error reading '%s'\n", x509_cafile
);
953 printf ("Processed %d CA certificate(s).\n", ret
);
957 if (x509_crlfile
!= NULL
)
959 if ((ret
= gnutls_certificate_set_x509_crl_file
960 (cert_cred
, x509_crlfile
, x509ctype
)) < 0)
962 fprintf (stderr
, "Error reading '%s'\n", x509_crlfile
);
968 printf ("Processed %d CRL(s).\n", ret
);
973 #ifdef ENABLE_OPENPGP
974 if (pgp_keyring
!= NULL
)
977 gnutls_certificate_set_openpgp_keyring_file (cert_cred
, pgp_keyring
,
978 GNUTLS_OPENPGP_FMT_BASE64
);
981 fprintf (stderr
, "Error setting the OpenPGP keyring file\n");
986 if (pgp_certfile
!= NULL
)
988 if (info
.pgp_subkey
!= NULL
)
989 ret
= gnutls_certificate_set_openpgp_key_file2
990 (cert_cred
, pgp_certfile
, pgp_keyfile
, info
.pgp_subkey
,
991 GNUTLS_OPENPGP_FMT_BASE64
);
993 ret
= gnutls_certificate_set_openpgp_key_file
994 (cert_cred
, pgp_certfile
, pgp_keyfile
, GNUTLS_OPENPGP_FMT_BASE64
);
999 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1000 ret
, pgp_certfile
, pgp_keyfile
);
1006 if (x509_certfile
!= NULL
)
1007 if ((ret
= gnutls_certificate_set_x509_key_file
1008 (cert_cred
, x509_certfile
, x509_keyfile
, x509ctype
)) < 0)
1011 "Error reading '%s' or '%s'\n", x509_certfile
, x509_keyfile
);
1016 if (x509_dsacertfile
!= NULL
)
1017 if ((ret
= gnutls_certificate_set_x509_key_file
1018 (cert_cred
, x509_dsacertfile
, x509_dsakeyfile
, x509ctype
)) < 0)
1020 fprintf (stderr
, "Error reading '%s' or '%s'\n",
1021 x509_dsacertfile
, x509_dsakeyfile
);
1026 gnutls_certificate_set_params_function (cert_cred
, get_params
);
1027 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1028 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1031 /* this is a password file (created with the included srpcrypt utility)
1032 * Read README.crypt prior to using SRP.
1035 if (srp_passwd
!= NULL
)
1037 gnutls_srp_allocate_server_credentials (&srp_cred
);
1040 gnutls_srp_set_server_credentials_file (srp_cred
, srp_passwd
,
1041 srp_passwd_conf
)) < 0)
1043 /* only exit is this function is not disabled
1045 fprintf (stderr
, "Error while setting SRP parameters\n");
1051 /* this is a password file
1054 if (psk_passwd
!= NULL
)
1056 gnutls_psk_allocate_server_credentials (&psk_cred
);
1059 gnutls_psk_set_server_credentials_file (psk_cred
, psk_passwd
)) < 0)
1061 /* only exit is this function is not disabled
1063 fprintf (stderr
, "Error while setting PSK parameters\n");
1069 ret
= gnutls_psk_set_server_credentials_hint (psk_cred
,
1073 fprintf (stderr
, "Error setting PSK identity hint.\n");
1078 gnutls_psk_set_server_params_function (psk_cred
, get_params
);
1083 gnutls_anon_allocate_server_credentials (&dh_cred
);
1084 gnutls_anon_set_server_params_function (dh_cred
, get_params
);
1086 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1089 #ifdef ENABLE_SESSION_TICKET
1091 gnutls_session_ticket_key_generate (&session_ticket_key
);
1094 if (listen_socket (name
, port
) < 0)
1107 /* flag which connections we are reading or writing to within the fd sets */
1108 lloopstart (listener_list
, j
)
1112 val
= fcntl (j
->fd
, F_GETFL
, 0);
1113 if ((val
== -1) || (fcntl (j
->fd
, F_SETFL
, val
| O_NONBLOCK
) < 0))
1120 if (j
->listen_socket
)
1122 FD_SET (j
->fd
, &rd
);
1125 if (j
->http_state
== HTTP_STATE_REQUEST
)
1127 FD_SET (j
->fd
, &rd
);
1130 if (j
->http_state
== HTTP_STATE_RESPONSE
)
1132 FD_SET (j
->fd
, &wr
);
1136 lloopend (listener_list
, j
);
1138 /* core operation */
1139 n
= select (n
+ 1, &rd
, &wr
, NULL
, NULL
);
1140 if (n
== -1 && errno
== EINTR
)
1144 perror ("select()");
1148 /* read or write to each connection as indicated by select()'s return argument */
1149 lloopstart (listener_list
, j
)
1152 /* a new connection has arrived */
1153 if (FD_ISSET (j
->fd
, &rd
) && j
->listen_socket
)
1155 gnutls_session_t tls_session
;
1157 tls_session
= initialize_session ();
1159 calen
= sizeof (client_address
);
1160 memset (&client_address
, 0, calen
);
1161 accept_fd
= accept (j
->fd
, (struct sockaddr
*) &client_address
,
1166 perror ("accept()");
1173 /* new list entry for the connection */
1174 lappend (listener_list
);
1175 j
= listener_list
.tail
;
1176 j
->http_request
= (char *) strdup ("");
1177 j
->http_state
= HTTP_STATE_REQUEST
;
1180 j
->tls_session
= tls_session
;
1181 gnutls_transport_set_ptr (tls_session
,
1182 (gnutls_transport_ptr_t
)
1183 gl_fd_to_handle (accept_fd
));
1184 j
->handshake_ok
= 0;
1190 ctt
[strlen (ctt
) - 1] = 0;
1192 printf ("\n* Accepted connection from %s on %s\n",
1193 human_addr ((struct sockaddr
*)
1194 &client_address
, calen
, topbuf
,
1195 sizeof (topbuf
)), ctt
);
1200 if (FD_ISSET (j
->fd
, &rd
) && !j
->listen_socket
)
1202 /* read partial GET request */
1206 if (j
->handshake_ok
== 0)
1208 r
= gnutls_handshake (j
->tls_session
);
1209 if (r
< 0 && gnutls_error_is_fatal (r
) == 0)
1211 check_alert (j
->tls_session
, r
);
1214 else if (r
< 0 && gnutls_error_is_fatal (r
) == 1)
1216 check_alert (j
->tls_session
, r
);
1217 fprintf (stderr
, "Error in handshake\n");
1223 gnutls_alert_send_appropriate (j
->tls_session
, r
);
1225 while (ret
== GNUTLS_E_AGAIN
);
1226 j
->http_state
= HTTP_STATE_CLOSING
;
1230 if (gnutls_session_is_resumed (j
->tls_session
) != 0
1232 printf ("*** This is a resumed session\n");
1236 printf ("\n* Successful handshake from %s\n",
1237 human_addr ((struct sockaddr
*)
1238 &client_address
, calen
, topbuf
,
1240 print_info (j
->tls_session
, NULL
, 1);
1242 j
->handshake_ok
= 1;
1246 if (j
->handshake_ok
== 1)
1248 r
= gnutls_record_recv (j
->tls_session
, buf
,
1249 MIN (1024, SMALL_READ_TEST
));
1250 if (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
)
1256 if (r
== GNUTLS_E_REHANDSHAKE
)
1258 fprintf(stderr
, "*** Received hello message\n");
1261 r
= gnutls_handshake (j
->tls_session
);
1263 while (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
);
1267 j
->http_state
= HTTP_STATE_CLOSING
;
1268 if (r
< 0 && r
!= GNUTLS_E_UNEXPECTED_PACKET_LENGTH
)
1270 check_alert (j
->tls_session
, r
);
1271 fprintf (stderr
, "Error while receiving data\n");
1279 realloc (j
->http_request
, j
->request_length
+ r
+ 1);
1280 if (j
->http_request
!= NULL
)
1282 memcpy (j
->http_request
+ j
->request_length
, buf
, r
);
1283 j
->request_length
+= r
;
1284 j
->http_request
[j
->request_length
] = '\0';
1287 j
->http_state
= HTTP_STATE_CLOSING
;
1290 /* check if we have a full HTTP header */
1292 j
->http_response
= NULL
;
1293 if (j
->http_request
!= NULL
)
1295 if ((http
== 0 && strchr (j
->http_request
, '\n'))
1296 || strstr (j
->http_request
, "\r\n\r\n")
1297 || strstr (j
->http_request
, "\n\n"))
1299 get_response (j
->tls_session
, j
->http_request
,
1300 &j
->http_response
, &j
->response_length
);
1301 j
->http_state
= HTTP_STATE_RESPONSE
;
1302 j
->response_written
= 0;
1307 if (FD_ISSET (j
->fd
, &wr
))
1309 /* write partial response request */
1312 if (j
->handshake_ok
== 0)
1314 r
= gnutls_handshake (j
->tls_session
);
1315 if (r
< 0 && gnutls_error_is_fatal (r
) == 0)
1317 check_alert (j
->tls_session
, r
);
1320 else if (r
< 0 && gnutls_error_is_fatal (r
) == 1)
1324 j
->http_state
= HTTP_STATE_CLOSING
;
1325 check_alert (j
->tls_session
, r
);
1326 fprintf (stderr
, "Error in handshake\n");
1332 gnutls_alert_send_appropriate (j
->tls_session
, r
);
1334 while (ret
== GNUTLS_E_AGAIN
);
1338 if (gnutls_session_is_resumed (j
->tls_session
) != 0
1340 printf ("*** This is a resumed session\n");
1343 printf ("- connection from %s\n",
1344 human_addr ((struct sockaddr
*)
1345 &client_address
, calen
, topbuf
,
1348 print_info (j
->tls_session
, NULL
, 1);
1350 j
->handshake_ok
= 1;
1354 if (j
->handshake_ok
== 1 && j
->http_response
!= NULL
)
1356 /* FIXME if j->http_response == NULL? */
1357 r
= gnutls_record_send (j
->tls_session
,
1359 j
->response_written
,
1360 MIN (j
->response_length
-
1361 j
->response_written
,
1363 if (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
)
1370 j
->http_state
= HTTP_STATE_CLOSING
;
1373 j
->http_state
= HTTP_STATE_REQUEST
;
1374 free (j
->http_response
);
1375 j
->response_length
= 0;
1376 j
->request_length
= 0;
1377 j
->http_request
[0] = 0;
1382 fprintf (stderr
, "Error while sending data\n");
1385 check_alert (j
->tls_session
, r
);
1389 j
->response_written
+= r
;
1390 /* check if we have written a complete response */
1391 if (j
->response_written
== j
->response_length
)
1394 j
->http_state
= HTTP_STATE_CLOSING
;
1397 j
->http_state
= HTTP_STATE_REQUEST
;
1398 free (j
->http_response
);
1399 j
->response_length
= 0;
1400 j
->request_length
= 0;
1401 j
->http_request
[0] = 0;
1408 j
->request_length
= 0;
1409 j
->http_request
[0] = 0;
1410 j
->http_state
= HTTP_STATE_REQUEST
;
1414 lloopend (listener_list
, j
);
1416 /* loop through all connections, closing those that are in error */
1417 lloopstart (listener_list
, j
)
1419 if (j
->http_state
== HTTP_STATE_CLOSING
)
1421 ldeleteinc (listener_list
, j
);
1424 lloopend (listener_list
, j
);
1428 gnutls_certificate_free_credentials (cert_cred
);
1432 gnutls_srp_free_server_credentials (srp_cred
);
1437 gnutls_psk_free_server_credentials (psk_cred
);
1441 gnutls_anon_free_server_credentials (dh_cred
);
1444 #ifdef ENABLE_SESSION_TICKET
1446 gnutls_free (session_ticket_key
.data
);
1451 gnutls_global_deinit ();
1458 gaa_parser (int argc
, char **argv
)
1460 if (gaa (argc
, argv
, &info
) != -1)
1463 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1467 disable_client_cert
= info
.disable_client_cert
;
1468 require_cert
= info
.require_cert
;
1470 verbose
= info
.quiet
;
1472 noticket
= info
.noticket
;
1479 if (info
.fmtder
== 0)
1480 x509ctype
= GNUTLS_X509_FMT_PEM
;
1482 x509ctype
= GNUTLS_X509_FMT_DER
;
1484 if (info
.generate
== 0)
1489 dh_params_file
= info
.dh_params_file
;
1493 x509_certfile
= info
.x509_certfile
;
1494 x509_keyfile
= info
.x509_keyfile
;
1495 x509_dsacertfile
= info
.x509_dsacertfile
;
1496 x509_dsakeyfile
= info
.x509_dsakeyfile
;
1497 x509_cafile
= info
.x509_cafile
;
1498 x509_crlfile
= info
.x509_crlfile
;
1499 pgp_certfile
= info
.pgp_certfile
;
1500 pgp_keyfile
= info
.pgp_keyfile
;
1501 srp_passwd
= info
.srp_passwd
;
1502 srp_passwd_conf
= info
.srp_passwd_conf
;
1504 psk_passwd
= info
.psk_passwd
;
1506 pgp_keyring
= info
.pgp_keyring
;
1508 parse_protocols (info
.proto
, info
.nproto
, protocol_priority
);
1509 parse_ciphers (info
.ciphers
, info
.nciphers
, cipher_priority
);
1510 parse_macs (info
.macs
, info
.nmacs
, mac_priority
);
1511 parse_ctypes (info
.ctype
, info
.nctype
, cert_type_priority
);
1512 parse_kx (info
.kx
, info
.nkx
, kx_priority
);
1513 parse_comp (info
.comp
, info
.ncomp
, comp_priority
);
1516 extern void serv_version (void);
1521 const char *p
= PACKAGE_NAME
;
1522 if (strcmp (gnutls_check_version (NULL
), PACKAGE_VERSION
) != 0)
1524 version_etc (stdout
, program_name
, p
, gnutls_check_version (NULL
),
1525 "Nikos Mavrogiannopoulos", (char *) NULL
);
1528 /* session resuming support */
1530 #define SESSION_ID_SIZE 32
1531 #define SESSION_DATA_SIZE 1024
1535 char session_id
[SESSION_ID_SIZE
];
1536 unsigned int session_id_size
;
1538 char session_data
[SESSION_DATA_SIZE
];
1539 unsigned int session_data_size
;
1542 static CACHE
*cache_db
;
1543 int cache_db_ptr
= 0;
1548 /* allocate cache_db */
1549 cache_db
= calloc (1, ssl_session_cache
* sizeof (CACHE
));
1553 wrap_db_deinit (void)
1558 wrap_db_store (void *dbf
, gnutls_datum_t key
, gnutls_datum_t data
)
1561 if (cache_db
== NULL
)
1564 if (key
.size
> SESSION_ID_SIZE
)
1566 if (data
.size
> SESSION_DATA_SIZE
)
1569 memcpy (cache_db
[cache_db_ptr
].session_id
, key
.data
, key
.size
);
1570 cache_db
[cache_db_ptr
].session_id_size
= key
.size
;
1572 memcpy (cache_db
[cache_db_ptr
].session_data
, data
.data
, data
.size
);
1573 cache_db
[cache_db_ptr
].session_data_size
= data
.size
;
1576 cache_db_ptr
%= ssl_session_cache
;
1581 static gnutls_datum_t
1582 wrap_db_fetch (void *dbf
, gnutls_datum_t key
)
1584 gnutls_datum_t res
= { NULL
, 0 };
1587 if (cache_db
== NULL
)
1590 for (i
= 0; i
< ssl_session_cache
; i
++)
1592 if (key
.size
== cache_db
[i
].session_id_size
&&
1593 memcmp (key
.data
, cache_db
[i
].session_id
, key
.size
) == 0)
1595 res
.size
= cache_db
[i
].session_data_size
;
1597 res
.data
= gnutls_malloc (res
.size
);
1598 if (res
.data
== NULL
)
1601 memcpy (res
.data
, cache_db
[i
].session_data
, res
.size
);
1610 wrap_db_delete (void *dbf
, gnutls_datum_t key
)
1614 if (cache_db
== NULL
)
1617 for (i
= 0; i
< ssl_session_cache
; i
++)
1619 if (key
.size
== (unsigned int) cache_db
[i
].session_id_size
&&
1620 memcmp (key
.data
, cache_db
[i
].session_id
, key
.size
) == 0)
1623 cache_db
[i
].session_id_size
= 0;
1624 cache_db
[i
].session_data_size
= 0;