2 * Copyright (C) 2004-2012 Free Software Foundation, Inc.
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)
29 #include "serv-args.h"
33 #include <sys/types.h>
35 #include <gnutls/gnutls.h>
36 #include <gnutls/dtls.h>
37 #include <gnutls/openpgp.h>
39 #include <sys/select.h>
46 /* Gnulib portability files. */
47 #include "read-file.h"
52 /* konqueror cannot handle sending the page in multiple
56 static int generate = 0;
61 unsigned int verbose = 1;
65 int disable_client_cert;
67 const char *psk_passwd = NULL;
68 const char *srp_passwd = NULL;
69 const char *srp_passwd_conf = NULL;
70 const char *pgp_keyring = NULL;
71 const char *pgp_keyfile = NULL;
72 const char *pgp_certfile = NULL;
73 const char *x509_keyfile = NULL;
74 const char *x509_certfile = NULL;
75 const char *x509_dsakeyfile = NULL;
76 const char *x509_dsacertfile = NULL;
77 const char *x509_ecckeyfile = NULL;
78 const char *x509_ecccertfile = NULL;
79 const char *x509_cafile = NULL;
80 const char *dh_params_file = NULL;
81 const char *x509_crlfile = NULL;
82 const char *priorities = NULL;
83 const char *status_response_ocsp = NULL;
85 gnutls_datum_t session_ticket_key;
86 static void tcp_server(const char *name, int port);
90 /* This is a sample TCP echo server.
91 * This will behave as an http server if any argument in the
92 * command line is present
95 #define SMALL_READ_TEST (2147483647)
97 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
99 #define HTTP_END "</BODY></HTML>\n\n"
101 #define HTTP_UNIMPLEMENTED "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML><HEAD>\r\n<TITLE>501 Method Not Implemented</TITLE>\r\n</HEAD><BODY>\r\n<H1>Method Not Implemented</H1>\r\n<HR>\r\n</BODY></HTML>\r\n"
102 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
104 #define HTTP_BEGIN HTTP_OK \
107 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
108 "GnuTLS</a></H1></CENTER>\n\n"
110 /* These are global */
111 gnutls_srp_server_credentials_t srp_cred = NULL;
112 gnutls_psk_server_credentials_t psk_cred = NULL;
113 gnutls_anon_server_credentials_t dh_cred = NULL;
114 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,
121 gnutls_datum_t data);
122 static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key);
123 static int wrap_db_delete(void *dbf, gnutls_datum_t key);
125 static void cmd_parser(int argc, char **argv);
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; char *http_response;
133 int request_length; int response_length;
134 int response_written; int http_state;
135 int listen_socket; int fd;
136 gnutls_session_t tls_session;
141 static const char *safe_strerror(int value)
143 const char *ret = gnutls_strerror(value);
149 static void listener_free(listener_item * j)
152 free(j->http_request);
153 free(j->http_response);
155 gnutls_bye(j->tls_session, GNUTLS_SHUT_WR);
158 gnutls_deinit(j->tls_session);
163 /* we use primes up to 1024 in this server.
164 * otherwise we should add them here.
167 gnutls_dh_params_t dh_params = NULL;
168 gnutls_rsa_params_t rsa_params = NULL;
170 static int generate_dh_primes(void)
173 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
174 GNUTLS_SEC_PARAM_MEDIUM);
176 if (gnutls_dh_params_init(&dh_params) < 0) {
177 fprintf(stderr, "Error in dh parameter initialization\n");
181 /* Generate Diffie-Hellman parameters - for use with DHE
182 * kx algorithms. These should be discarded and regenerated
183 * once a week or once a month. Depends on the
184 * security requirements.
187 ("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
191 if (gnutls_dh_params_generate2(dh_params, prime_bits) < 0) {
192 fprintf(stderr, "Error in prime generation\n");
199 static void read_dh_params(void)
203 gnutls_datum_t params;
206 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");
215 fprintf(stderr, "Could not open %s\n", dh_params_file);
219 size = fread(tmpdata, 1, sizeof(tmpdata) - 1, fd);
223 params.data = (unsigned char *) tmpdata;
227 gnutls_dh_params_import_pkcs3(dh_params, ¶ms,
228 GNUTLS_X509_FMT_PEM);
231 fprintf(stderr, "Error parsing dh params: %s\n",
232 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";
248 static int static_dh_params(void)
250 gnutls_datum_t params = { (void *) pkcs3, sizeof(pkcs3) };
253 if (gnutls_dh_params_init(&dh_params) < 0) {
254 fprintf(stderr, "Error in dh parameter initialization\n");
258 ret = gnutls_dh_params_import_pkcs3(dh_params, ¶ms,
259 GNUTLS_X509_FMT_PEM);
262 fprintf(stderr, "Error parsing dh params: %s\n",
268 ("Set static Diffie-Hellman parameters, consider --dhparams.\n");
274 get_params(gnutls_session_t session, gnutls_params_type_t type,
275 gnutls_params_st * st)
278 if (type == GNUTLS_PARAMS_DH) {
279 if (dh_params == NULL)
281 st->params.dh = dh_params;
291 LIST_DECLARE_INIT(listener_list, listener_item, listener_free);
293 static int cert_verify_callback(gnutls_session_t session)
295 listener_item * j = gnutls_session_get_ptr(session);
299 if (gnutls_auth_get_type(session) == GNUTLS_CRD_CERTIFICATE) {
300 if (!require_cert && gnutls_certificate_get_peers(session, &size) == NULL)
303 if (require_cert || ENABLED_OPT(VERIFY_CLIENT_CERT)) {
304 if (cert_verify(session, NULL, NULL) == 0) {
306 ret = gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
307 } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
309 j->http_state = HTTP_STATE_CLOSING;
313 printf("- Peer's certificate was NOT verified.\n");
319 gnutls_session_t initialize_session(int dtls)
321 gnutls_session_t session;
325 if (priorities == NULL)
326 priorities = "NORMAL";
329 gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
331 gnutls_init(&session, GNUTLS_SERVER);
333 /* allow the use of private ciphersuites.
335 gnutls_handshake_set_private_extensions(session, 1);
338 gnutls_db_set_retrieve_function(session, wrap_db_fetch);
339 gnutls_db_set_remove_function(session, wrap_db_delete);
340 gnutls_db_set_store_function(session, wrap_db_store);
341 gnutls_db_set_ptr(session, NULL);
344 #ifdef ENABLE_SESSION_TICKETS
346 gnutls_session_ticket_enable_server(session,
347 &session_ticket_key);
350 if (gnutls_priority_set_direct(session, priorities, &err) < 0) {
351 fprintf(stderr, "Syntax error at: %s\n", err);
355 gnutls_credentials_set(session, GNUTLS_CRD_ANON, dh_cred);
357 if (srp_cred != NULL)
358 gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred);
360 if (psk_cred != NULL)
361 gnutls_credentials_set(session, GNUTLS_CRD_PSK, psk_cred);
363 if (cert_cred != NULL) {
364 gnutls_certificate_set_verify_function(cert_cred,
365 cert_verify_callback);
367 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
371 if (disable_client_cert)
372 gnutls_certificate_server_set_request(session,
376 gnutls_certificate_server_set_request(session,
377 GNUTLS_CERT_REQUIRE);
379 gnutls_certificate_server_set_request(session,
380 GNUTLS_CERT_REQUEST);
383 if (HAVE_OPT(HEARTBEAT))
384 gnutls_heartbeat_enable(session,
385 GNUTLS_HB_PEER_ALLOWED_TO_SEND);
387 #ifdef ENABLE_DTLS_SRTP
388 if (HAVE_OPT(SRTP_PROFILES)) {
390 gnutls_srtp_set_profile_direct(session,
391 OPT_ARG(SRTP_PROFILES),
393 if (ret == GNUTLS_E_INVALID_REQUEST)
394 fprintf(stderr, "Syntax error at: %s\n", err);
396 fprintf(stderr, "Error in profiles: %s\n",
397 gnutls_strerror(ret));
398 else fprintf(stderr,"DTLS profile set to %s\n",
399 OPT_ARG(SRTP_PROFILES));
401 if (ret != 0) exit(1);
409 #include <gnutls/x509.h>
411 static const char DEFAULT_DATA[] =
412 "This is the default message reported by the GnuTLS implementation. "
413 "For more information please visit "
414 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
416 /* Creates html with the current session information.
418 #define tmp_buffer &http_buffer[strlen(http_buffer)]
419 #define tmp_buffer_size len-strlen(http_buffer)
420 static char *peer_print_info(gnutls_session_t session, int *ret_length,
424 unsigned char sesid[32];
425 size_t i, sesid_size;
427 gnutls_kx_algorithm_t kx_alg;
428 size_t len = 20 * 1024 + strlen(header);
429 char *crtinfo = NULL, *crtinfo_old = NULL;
433 http_buffer = malloc(len);
434 if (http_buffer == NULL)
437 strcpy(http_buffer, HTTP_BEGIN);
438 strcpy(&http_buffer[sizeof(HTTP_BEGIN) - 1], DEFAULT_DATA);
440 [sizeof(HTTP_BEGIN) + sizeof(DEFAULT_DATA) - 2],
443 sizeof(DEFAULT_DATA) + sizeof(HTTP_BEGIN) +
444 sizeof(HTTP_END) - 3;
448 if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
449 const gnutls_datum_t *cert_list;
450 unsigned int cert_list_size = 0;
453 gnutls_certificate_get_peers(session, &cert_list_size);
455 for (i = 0; i < cert_list_size; i++) {
456 gnutls_x509_crt_t cert;
459 if (gnutls_x509_crt_init(&cert) == 0 &&
460 gnutls_x509_crt_import(cert, &cert_list[i],
461 GNUTLS_X509_FMT_DER) ==
463 && gnutls_x509_crt_print(cert,
464 GNUTLS_CRT_PRINT_FULL,
466 const char *post = "</PRE><P><PRE>";
468 crtinfo_old = crtinfo;
471 ncrtinfo + info.size +
473 if (crtinfo == NULL) {
477 memcpy(crtinfo + ncrtinfo, info.data,
479 ncrtinfo += info.size;
480 memcpy(crtinfo + ncrtinfo, post,
482 ncrtinfo += strlen(post);
483 crtinfo[ncrtinfo] = '\0';
484 gnutls_free(info.data);
489 http_buffer = malloc(len);
490 if (http_buffer == NULL) {
495 strcpy(http_buffer, HTTP_BEGIN);
497 /* print session_id */
498 sesid_size = sizeof(sesid);
499 gnutls_session_get_id(session, sesid, &sesid_size);
500 snprintf(tmp_buffer, tmp_buffer_size, "\n<p>Session ID: <i>");
501 for (i = 0; i < sesid_size; i++)
502 snprintf(tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
503 snprintf(tmp_buffer, tmp_buffer_size, "</i></p>\n");
504 snprintf(tmp_buffer, tmp_buffer_size,
505 "<h5>If your browser supports session resuming, then you should see the "
506 "same session ID, when you press the <b>reload</b> button.</h5>\n");
508 /* Here unlike print_info() we use the kx algorithm to distinguish
509 * the functions to call.
513 size_t dns_size = sizeof(dns);
516 if (gnutls_server_name_get
517 (session, dns, &dns_size, &type, 0) == 0) {
518 snprintf(tmp_buffer, tmp_buffer_size,
519 "\n<p>Server Name: %s</p>\n", dns);
524 kx_alg = gnutls_kx_get(session);
526 /* print srp specific data */
528 if (kx_alg == GNUTLS_KX_SRP) {
529 snprintf(tmp_buffer, tmp_buffer_size,
530 "<p>Connected as user '%s'.</p>\n",
531 gnutls_srp_server_get_username(session));
536 if (kx_alg == GNUTLS_KX_PSK) {
537 snprintf(tmp_buffer, tmp_buffer_size,
538 "<p>Connected as user '%s'.</p>\n",
539 gnutls_psk_server_get_username(session));
544 if (kx_alg == GNUTLS_KX_ANON_DH) {
545 snprintf(tmp_buffer, tmp_buffer_size,
546 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
547 gnutls_dh_get_prime_bits(session));
551 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS) {
552 snprintf(tmp_buffer, tmp_buffer_size,
553 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
554 gnutls_dh_get_prime_bits(session));
557 /* print session information */
558 strcat(http_buffer, "<P>\n");
561 gnutls_protocol_get_name(gnutls_protocol_get_version(session));
564 snprintf(tmp_buffer, tmp_buffer_size,
565 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
568 if (gnutls_auth_get_type(session) == GNUTLS_CRD_CERTIFICATE) {
570 gnutls_certificate_type_get_name
571 (gnutls_certificate_type_get(session));
574 snprintf(tmp_buffer, tmp_buffer_size,
575 "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n",
579 tmp = gnutls_kx_get_name(kx_alg);
582 snprintf(tmp_buffer, tmp_buffer_size,
583 "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
585 tmp = gnutls_compression_get_name(gnutls_compression_get(session));
588 snprintf(tmp_buffer, tmp_buffer_size,
589 "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
591 tmp = gnutls_cipher_get_name(gnutls_cipher_get(session));
594 snprintf(tmp_buffer, tmp_buffer_size,
595 "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
597 tmp = gnutls_mac_get_name(gnutls_mac_get(session));
600 snprintf(tmp_buffer, tmp_buffer_size,
601 "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
603 tmp = gnutls_cipher_suite_get_name(kx_alg,
604 gnutls_cipher_get(session),
605 gnutls_mac_get(session));
608 snprintf(tmp_buffer, tmp_buffer_size,
609 "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
613 snprintf(tmp_buffer, tmp_buffer_size,
614 "<hr><PRE>%s\n</PRE>\n", crtinfo);
618 snprintf(tmp_buffer, tmp_buffer_size,
619 "<hr><P>Your HTTP header was:<PRE>%s</PRE></P>\n"
622 *ret_length = strlen(http_buffer);
627 const char *human_addr(const struct sockaddr *sa, socklen_t salen,
628 char *buf, size_t buflen)
630 const char *save_buf = buf;
638 switch (sa->sa_family) {
641 snprintf(buf, buflen, "IPv6 ");
646 snprintf(buf, buflen, "IPv4 ");
654 if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) !=
666 strcat(buf, " port ");
670 if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) !=
672 snprintf(buf, buflen, "%s", " unknown");
678 int wait_for_connection(void)
688 lloopstart(listener_list, j) {
689 if (j->listen_socket) {
694 lloopend(listener_list, j);
697 n = select(n + 1, &rd, &wr, NULL, NULL);
698 if (n == -1 && errno == EINTR)
705 /* find which one is ready */
706 lloopstart(listener_list, j) {
707 /* a new connection has arrived */
708 if (FD_ISSET(j->fd, &rd) && j->listen_socket) {
713 lloopend(listener_list, j);
717 int listen_socket(const char *name, int listen_port, int socktype)
719 struct addrinfo hints, *res, *ptr;
723 listener_item *j = NULL;
725 snprintf(portname, sizeof(portname), "%d", listen_port);
726 memset(&hints, 0, sizeof(hints));
727 hints.ai_socktype = socktype;
728 hints.ai_flags = AI_PASSIVE
734 if ((s = getaddrinfo(NULL, portname, &hints, &res)) != 0) {
735 fprintf(stderr, "getaddrinfo() failed: %s\n",
740 for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
743 if (ptr->ai_family != AF_INET)
747 /* Print what we are doing. */
751 fprintf(stderr, "%s listening on %s...",
752 name, human_addr(ptr->ai_addr,
753 ptr->ai_addrlen, topbuf,
757 if ((news = socket(ptr->ai_family, ptr->ai_socktype,
758 ptr->ai_protocol)) < 0) {
759 perror("socket() failed");
762 s = news; /* to not overwrite existing s from previous loops */
763 #if defined(HAVE_IPV6) && !defined(_WIN32)
764 if (ptr->ai_family == AF_INET6) {
766 /* avoid listen on ipv6 addresses failing
767 * because already listening on ipv4 addresses: */
768 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
769 (const void *) &yes, sizeof(yes));
773 if (socktype == SOCK_STREAM) {
775 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
778 perror("setsockopt() failed");
783 #if defined(IP_DONTFRAG)
785 if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
788 perror("setsockopt(IP_DF) failed");
789 #elif defined(IP_MTU_DISCOVER)
790 yes = IP_PMTUDISC_DO;
791 if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
794 perror("setsockopt(IP_DF) failed");
798 if (bind(s, ptr->ai_addr, ptr->ai_addrlen) < 0) {
799 perror("bind() failed");
804 if (socktype == SOCK_STREAM) {
805 if (listen(s, 10) < 0) {
806 perror("listen() failed");
811 /* new list entry for the connection */
812 lappend(listener_list);
813 j = listener_list.tail;
814 j->listen_socket = 1;
817 /* Complete earlier message. */
818 fprintf(stderr, "done\n");
828 /* strips \r\n from the end of the string
830 static void strip(char *data)
833 int len = strlen(data);
835 for (i = 0; i < len; i++) {
836 if (data[i] == '\r' && data[i + 1] == '\n'
837 && data[i + 1] == 0) {
846 get_response(gnutls_session_t session, char *request,
847 char **response, int *response_length)
852 if (strncmp(request, "GET ", 4))
855 if (!(h = strchr(request, '\n')))
859 while (*h == '\r' || *h == '\n')
862 if (!(p = strchr(request + 4, ' ')))
866 /* *response = peer_print_info(session, request+4, h, response_length); */
868 *response = peer_print_info(session, response_length, h);
871 fprintf(stderr, "received: %s\n", request);
872 if (check_command(session, request)) {
874 *response_length = 0;
877 *response = strdup(request);
878 *response_length = ((*response) ? strlen(*response) : 0);
884 *response = strdup(HTTP_UNIMPLEMENTED);
885 *response_length = ((*response) ? strlen(*response) : 0);
888 static void terminate(int sig) __attribute__ ((noreturn));
890 static void terminate(int sig)
892 fprintf(stderr, "Exiting via signal %d\n", sig);
897 static void check_alert(gnutls_session_t session, int ret)
899 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
900 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
901 int last_alert = gnutls_alert_get(session);
902 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
903 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
905 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
907 printf("* Received alert '%d': %s.\n", last_alert,
908 gnutls_alert_get_name(last_alert));
912 static void tls_log_func(int level, const char *str)
914 fprintf(stderr, "|<%d>| %s", level, str);
917 static void tls_audit_log_func(gnutls_session_t session, const char *str)
919 fprintf(stderr, "|<%p>| %s", session, str);
922 int main(int argc, char **argv)
928 cmd_parser(argc, argv);
931 signal(SIGHUP, SIG_IGN);
932 signal(SIGTERM, terminate);
933 if (signal(SIGINT, terminate) == SIG_IGN)
934 signal(SIGINT, SIG_IGN); /* e.g. background process */
943 strcpy(name, "UDP ");
948 strcat(name, "HTTP Server");
950 strcat(name, "Echo Server");
953 gnutls_global_set_log_function(tls_log_func);
954 gnutls_global_set_audit_log_function(tls_audit_log_func);
955 gnutls_global_set_log_level(debug);
957 if ((ret = gnutls_global_init()) < 0) {
958 fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret));
962 if (HAVE_OPT(PROVIDER)) {
963 ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
965 fprintf(stderr, "pkcs11_init: %s",
966 gnutls_strerror(ret));
969 gnutls_pkcs11_add_provider(OPT_ARG(PROVIDER),
972 fprintf(stderr, "pkcs11_add_provider: %s",
973 gnutls_strerror(ret));
981 /* Note that servers must generate parameters for
982 * Diffie-Hellman. See gnutls_dh_params_generate(), and
983 * gnutls_dh_params_set().
986 generate_dh_primes();
987 } else if (dh_params_file) {
993 if (gnutls_certificate_allocate_credentials(&cert_cred) < 0) {
994 fprintf(stderr, "memory error\n");
998 if (x509_cafile != NULL) {
999 if ((ret = gnutls_certificate_set_x509_trust_file
1000 (cert_cred, x509_cafile, x509ctype)) < 0) {
1001 fprintf(stderr, "Error reading '%s'\n",
1006 printf("Processed %d CA certificate(s).\n", ret);
1009 if (x509_crlfile != NULL) {
1010 if ((ret = gnutls_certificate_set_x509_crl_file
1011 (cert_cred, x509_crlfile, x509ctype)) < 0) {
1012 fprintf(stderr, "Error reading '%s'\n",
1017 printf("Processed %d CRL(s).\n", ret);
1020 #ifdef ENABLE_OPENPGP
1021 if (pgp_keyring != NULL) {
1023 gnutls_certificate_set_openpgp_keyring_file(cert_cred,
1025 GNUTLS_OPENPGP_FMT_BASE64);
1028 "Error setting the OpenPGP keyring file\n");
1033 if (pgp_certfile != NULL && pgp_keyfile != NULL) {
1034 if (HAVE_OPT(PGPSUBKEY))
1035 ret = gnutls_certificate_set_openpgp_key_file2
1036 (cert_cred, pgp_certfile, pgp_keyfile,
1038 GNUTLS_OPENPGP_FMT_BASE64);
1040 ret = gnutls_certificate_set_openpgp_key_file
1041 (cert_cred, pgp_certfile, pgp_keyfile,
1042 GNUTLS_OPENPGP_FMT_BASE64);
1046 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1047 ret, pgp_certfile, pgp_keyfile);
1054 if (x509_certfile != NULL && x509_keyfile != NULL) {
1055 ret = gnutls_certificate_set_x509_key_file
1056 (cert_cred, x509_certfile, x509_keyfile, x509ctype);
1059 "Error reading '%s' or '%s'\n",
1060 x509_certfile, x509_keyfile);
1067 if (x509_dsacertfile != NULL && x509_dsakeyfile != NULL) {
1068 ret = gnutls_certificate_set_x509_key_file
1069 (cert_cred, x509_dsacertfile, x509_dsakeyfile,
1073 "Error reading '%s' or '%s'\n",
1074 x509_dsacertfile, x509_dsakeyfile);
1081 if (x509_ecccertfile != NULL && x509_ecckeyfile != NULL) {
1082 ret = gnutls_certificate_set_x509_key_file
1083 (cert_cred, x509_ecccertfile, x509_ecckeyfile,
1087 "Error reading '%s' or '%s'\n",
1088 x509_ecccertfile, x509_ecckeyfile);
1095 if (cert_set == 0) {
1097 "Warning: no private key and certificate pairs were set.\n");
1100 /* OCSP status-request TLS extension */
1101 if (status_response_ocsp) {
1102 if (gnutls_certificate_set_ocsp_status_request_file
1103 (cert_cred, status_response_ocsp, 0) < 0) {
1105 "Cannot set OCSP status request file: %s\n",
1106 gnutls_strerror(ret));
1111 gnutls_certificate_set_params_function(cert_cred, get_params);
1112 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1113 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1116 /* this is a password file (created with the included srpcrypt utility)
1117 * Read README.crypt prior to using SRP.
1120 if (srp_passwd != NULL) {
1121 gnutls_srp_allocate_server_credentials(&srp_cred);
1124 gnutls_srp_set_server_credentials_file(srp_cred,
1128 /* only exit is this function is not disabled
1131 "Error while setting SRP parameters\n");
1137 /* this is a password file
1140 if (psk_passwd != NULL) {
1141 gnutls_psk_allocate_server_credentials(&psk_cred);
1144 gnutls_psk_set_server_credentials_file(psk_cred,
1147 /* only exit is this function is not disabled
1150 "Error while setting PSK parameters\n");
1154 if (HAVE_OPT(PSKHINT)) {
1156 gnutls_psk_set_server_credentials_hint
1157 (psk_cred, OPT_ARG(PSKHINT));
1160 "Error setting PSK identity hint.\n");
1165 gnutls_psk_set_server_params_function(psk_cred,
1171 gnutls_anon_allocate_server_credentials(&dh_cred);
1172 gnutls_anon_set_server_params_function(dh_cred, get_params);
1174 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1177 #ifdef ENABLE_SESSION_TICKETS
1179 gnutls_session_ticket_key_generate(&session_ticket_key);
1183 mtu = OPT_VALUE_MTU;
1188 port = OPT_VALUE_PORT;
1193 udp_server(name, port, mtu);
1195 tcp_server(name, port);
1200 static void retry_handshake(listener_item *j)
1204 r = gnutls_handshake(j->tls_session);
1205 if (r < 0 && gnutls_error_is_fatal(r) == 0) {
1206 check_alert(j->tls_session, r);
1209 j->http_state = HTTP_STATE_CLOSING;
1210 check_alert(j->tls_session, r);
1211 fprintf(stderr, "Error in handshake\n");
1215 ret = gnutls_alert_send_appropriate(j->tls_session, r);
1216 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
1217 } else if (r == 0) {
1218 if (gnutls_session_is_resumed(j->tls_session) != 0 && verbose != 0)
1219 printf("*** This is a resumed session\n");
1223 printf("- connection from %s\n",
1224 human_addr((struct sockaddr *)
1231 print_info(j->tls_session, verbose, verbose);
1234 j->handshake_ok = 1;
1238 static void try_rehandshake(listener_item *j)
1241 fprintf(stderr, "*** Received hello message\n");
1243 r = gnutls_handshake(j->tls_session);
1244 } while (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN);
1248 ret = gnutls_alert_send_appropriate(j->tls_session, r);
1249 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
1251 j->http_state = HTTP_STATE_CLOSING;
1253 j->http_state = HTTP_STATE_REQUEST;
1257 static void tcp_server(const char *name, int port)
1262 struct sockaddr_storage client_address;
1266 s = listen_socket(name, port, SOCK_STREAM);
1273 time_t now = time(0);
1282 /* flag which connections we are reading or writing to within the fd sets */
1283 lloopstart(listener_list, j) {
1286 val = fcntl(j->fd, F_GETFL, 0);
1288 || (fcntl(j->fd, F_SETFL, val | O_NONBLOCK) <
1294 if (j->start != 0 && now - j->start > 30) {
1296 fprintf(stderr, "Scheduling inactive connection for close\n");
1298 j->http_state = HTTP_STATE_CLOSING;
1301 if (j->listen_socket) {
1305 if (j->http_state == HTTP_STATE_REQUEST) {
1309 if (j->http_state == HTTP_STATE_RESPONSE) {
1314 lloopend(listener_list, j);
1316 /* core operation */
1319 n = select(n + 1, &rd, &wr, NULL, &tv);
1320 if (n == -1 && errno == EINTR)
1327 /* read or write to each connection as indicated by select()'s return argument */
1328 lloopstart(listener_list, j) {
1330 /* a new connection has arrived */
1331 if (FD_ISSET(j->fd, &rd) && j->listen_socket) {
1332 calen = sizeof(client_address);
1333 memset(&client_address, 0, calen);
1337 &client_address, &calen);
1339 if (accept_fd < 0) {
1342 time_t tt = time(0);
1345 /* new list entry for the connection */
1346 lappend(listener_list);
1347 j = listener_list.tail;
1349 (char *) strdup("");
1350 j->http_state = HTTP_STATE_REQUEST;
1354 j->tls_session = initialize_session(0);
1355 gnutls_session_set_ptr(j->tls_session, j);
1356 gnutls_transport_set_int
1357 (j->tls_session, accept_fd);
1358 set_read_funcs(j->tls_session);
1359 j->handshake_ok = 0;
1363 ctt[strlen(ctt) - 1] = 0;
1366 ("\n* Accepted connection from %s on %s\n",
1380 if (FD_ISSET(j->fd, &rd) && !j->listen_socket) {
1381 /* read partial GET request */
1385 if (j->handshake_ok == 0) {
1389 if (j->handshake_ok == 1) {
1390 r = gnutls_record_recv(j->
1395 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
1397 } else if (r <= 0) {
1398 if (r == GNUTLS_E_HEARTBEAT_PING_RECEIVED) {
1399 gnutls_heartbeat_pong(j->tls_session, 0);
1400 } else if (r == GNUTLS_E_REHANDSHAKE) {
1403 j->http_state = HTTP_STATE_CLOSING;
1406 check_alert(j->tls_session, r);
1408 "Error while receiving data\n");
1410 ret = gnutls_alert_send_appropriate(j->tls_session, r);
1411 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
1422 if (j->http_request !=
1440 /* check if we have a full HTTP header */
1442 j->http_response = NULL;
1443 if (j->http_state == HTTP_STATE_REQUEST && j->http_request != NULL) {
1463 HTTP_STATE_RESPONSE;
1471 if (FD_ISSET(j->fd, &wr)) {
1472 /* write partial response request */
1475 if (j->handshake_ok == 0) {
1479 if (j->handshake_ok == 1 && j->http_response == NULL) {
1480 j->http_state = HTTP_STATE_CLOSING;
1481 } else if (j->handshake_ok == 1 && j->http_response != NULL) {
1482 r = gnutls_record_send(j->tls_session,
1485 j->response_written,
1486 MIN(j->response_length
1488 j->response_written,
1490 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
1492 } else if (r <= 0) {
1493 j->http_state = HTTP_STATE_CLOSING;
1496 "Error while sending data\n");
1499 check_alert(j->tls_session,
1502 j->response_written += r;
1503 /* check if we have written a complete response */
1504 if (j->response_written ==
1505 j->response_length) {
1507 j->http_state = HTTP_STATE_CLOSING;
1509 j->http_state = HTTP_STATE_REQUEST;
1512 j->response_length = 0;
1513 j->request_length = 0;
1514 j->http_request[0] = 0;
1519 j->request_length = 0;
1520 j->http_request[0] = 0;
1521 j->http_state = HTTP_STATE_REQUEST;
1525 lloopend(listener_list, j);
1527 /* loop through all connections, closing those that are in error */
1528 lloopstart(listener_list, j) {
1529 if (j->http_state == HTTP_STATE_CLOSING) {
1530 ldeleteinc(listener_list, j);
1533 lloopend(listener_list, j);
1537 gnutls_certificate_free_credentials(cert_cred);
1541 gnutls_srp_free_server_credentials(srp_cred);
1546 gnutls_psk_free_server_credentials(psk_cred);
1550 gnutls_anon_free_server_credentials(dh_cred);
1554 gnutls_free(session_ticket_key.data);
1558 gnutls_global_deinit();
1562 static void cmd_parser(int argc, char **argv)
1564 optionProcess(&gnutls_servOptions, argc, argv);
1566 disable_client_cert = HAVE_OPT(DISABLE_CLIENT_CERT);
1567 require_cert = ENABLED_OPT(REQUIRE_CLIENT_CERT);
1568 if (HAVE_OPT(DEBUG))
1569 debug = OPT_VALUE_DEBUG;
1571 if (HAVE_OPT(QUIET))
1574 if (HAVE_OPT(PRIORITY))
1575 priorities = OPT_ARG(PRIORITY);
1577 if (HAVE_OPT(LIST)) {
1578 print_list(priorities, verbose);
1582 nodb = HAVE_OPT(NODB);
1583 noticket = HAVE_OPT(NOTICKET);
1590 if (HAVE_OPT(X509FMTDER))
1591 x509ctype = GNUTLS_X509_FMT_DER;
1593 x509ctype = GNUTLS_X509_FMT_PEM;
1595 generate = HAVE_OPT(GENERATE);
1597 if (HAVE_OPT(DHPARAMS))
1598 dh_params_file = OPT_ARG(DHPARAMS);
1600 if (HAVE_OPT(X509KEYFILE))
1601 x509_keyfile = OPT_ARG(X509KEYFILE);
1602 if (HAVE_OPT(X509CERTFILE))
1603 x509_certfile = OPT_ARG(X509CERTFILE);
1605 if (HAVE_OPT(X509DSAKEYFILE))
1606 x509_dsakeyfile = OPT_ARG(X509DSAKEYFILE);
1607 if (HAVE_OPT(X509DSACERTFILE))
1608 x509_dsacertfile = OPT_ARG(X509DSACERTFILE);
1611 if (HAVE_OPT(X509ECCKEYFILE))
1612 x509_ecckeyfile = OPT_ARG(X509ECCKEYFILE);
1613 if (HAVE_OPT(X509ECCCERTFILE))
1614 x509_ecccertfile = OPT_ARG(X509ECCCERTFILE);
1616 if (HAVE_OPT(X509CAFILE))
1617 x509_cafile = OPT_ARG(X509CAFILE);
1618 if (HAVE_OPT(X509CRLFILE))
1619 x509_crlfile = OPT_ARG(X509CRLFILE);
1621 if (HAVE_OPT(PGPKEYFILE))
1622 pgp_keyfile = OPT_ARG(PGPKEYFILE);
1623 if (HAVE_OPT(PGPCERTFILE))
1624 pgp_certfile = OPT_ARG(PGPCERTFILE);
1626 if (HAVE_OPT(PGPKEYRING))
1627 pgp_keyring = OPT_ARG(PGPKEYRING);
1629 if (HAVE_OPT(SRPPASSWD))
1630 srp_passwd = OPT_ARG(SRPPASSWD);
1631 if (HAVE_OPT(SRPPASSWDCONF))
1632 srp_passwd_conf = OPT_ARG(SRPPASSWDCONF);
1634 if (HAVE_OPT(PSKPASSWD))
1635 psk_passwd = OPT_ARG(PSKPASSWD);
1637 if (HAVE_OPT(OCSP_RESPONSE))
1638 status_response_ocsp = OPT_ARG(OCSP_RESPONSE);
1642 /* session resuming support */
1644 #define SESSION_ID_SIZE 32
1645 #define SESSION_DATA_SIZE 1024
1648 char session_id[SESSION_ID_SIZE];
1649 unsigned int session_id_size;
1651 char session_data[SESSION_DATA_SIZE];
1652 unsigned int session_data_size;
1655 static CACHE *cache_db;
1656 int cache_db_ptr = 0;
1658 static void wrap_db_init(void)
1660 /* allocate cache_db */
1661 cache_db = calloc(1, ssl_session_cache * sizeof(CACHE));
1664 static void wrap_db_deinit(void)
1669 wrap_db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1672 if (cache_db == NULL)
1675 if (key.size > SESSION_ID_SIZE)
1677 if (data.size > SESSION_DATA_SIZE)
1680 memcpy(cache_db[cache_db_ptr].session_id, key.data, key.size);
1681 cache_db[cache_db_ptr].session_id_size = key.size;
1683 memcpy(cache_db[cache_db_ptr].session_data, data.data, data.size);
1684 cache_db[cache_db_ptr].session_data_size = data.size;
1687 cache_db_ptr %= ssl_session_cache;
1692 static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key)
1694 gnutls_datum_t res = { NULL, 0 };
1697 if (cache_db == NULL)
1700 for (i = 0; i < ssl_session_cache; i++) {
1701 if (key.size == cache_db[i].session_id_size &&
1702 memcmp(key.data, cache_db[i].session_id,
1704 res.size = cache_db[i].session_data_size;
1706 res.data = gnutls_malloc(res.size);
1707 if (res.data == NULL)
1710 memcpy(res.data, cache_db[i].session_data,
1719 static int wrap_db_delete(void *dbf, gnutls_datum_t key)
1723 if (cache_db == NULL)
1726 for (i = 0; i < ssl_session_cache; i++) {
1727 if (key.size == (unsigned int) cache_db[i].session_id_size
1728 && memcmp(key.data, cache_db[i].session_id,
1731 cache_db[i].session_id_size = 0;
1732 cache_db[i].session_data_size = 0;