|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2004-2012 Free Software Foundation, Inc.
|
|
Packit Service |
4684c1 |
* Copyright (C) 2001,2002 Paul Sheer
|
|
Packit Service |
4684c1 |
* Copyright (C) 2016-2018 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
* Portions Copyright (C) 2002,2003 Nikos Mavrogiannopoulos
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* GnuTLS is free software: you can redistribute it and/or modify
|
|
Packit Service |
4684c1 |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
4684c1 |
* the Free Software Foundation, either version 3 of the License, or
|
|
Packit Service |
4684c1 |
* (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* GnuTLS is distributed in the hope that it will be useful,
|
|
Packit Service |
4684c1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
4684c1 |
* GNU General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This server is heavily modified for GnuTLS by Nikos Mavrogiannopoulos
|
|
Packit Service |
4684c1 |
* (which means it is quite unreadable)
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <config.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "common.h"
|
|
Packit Service |
4684c1 |
#include "serv-args.h"
|
|
Packit Service |
4684c1 |
#include <stdio.h>
|
|
Packit Service |
4684c1 |
#include <stdlib.h>
|
|
Packit Service |
4684c1 |
#include <errno.h>
|
|
Packit Service |
4684c1 |
#include <sys/types.h>
|
|
Packit Service |
4684c1 |
#include <string.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/gnutls.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/dtls.h>
|
|
Packit Service |
4684c1 |
#include <sys/time.h>
|
|
Packit Service |
4684c1 |
#include <sys/select.h>
|
|
Packit Service |
4684c1 |
#include <fcntl.h>
|
|
Packit Service |
4684c1 |
#include <list.h>
|
|
Packit Service |
4684c1 |
#include <netdb.h>
|
|
Packit Service |
4684c1 |
#include <unistd.h>
|
|
Packit Service |
4684c1 |
#include <socket.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Gnulib portability files. */
|
|
Packit Service |
4684c1 |
#include "read-file.h"
|
|
Packit Service |
4684c1 |
#include "minmax.h"
|
|
Packit Service |
4684c1 |
#include "sockets.h"
|
|
Packit Service |
4684c1 |
#include "udp-serv.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* konqueror cannot handle sending the page in multiple
|
|
Packit Service |
4684c1 |
* pieces.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
/* global stuff */
|
|
Packit Service |
4684c1 |
static int generate = 0;
|
|
Packit Service |
4684c1 |
static int http = 0;
|
|
Packit Service |
4684c1 |
static int x509ctype;
|
|
Packit Service |
4684c1 |
static int debug = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
unsigned int verbose = 1;
|
|
Packit Service |
4684c1 |
static int nodb;
|
|
Packit Service |
4684c1 |
static int noticket;
|
|
Packit Service |
4684c1 |
static int earlydata;
|
|
Packit Service |
4684c1 |
int require_cert;
|
|
Packit Service |
4684c1 |
int disable_client_cert;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char *psk_passwd = NULL;
|
|
Packit Service |
4684c1 |
const char *srp_passwd = NULL;
|
|
Packit Service |
4684c1 |
const char *srp_passwd_conf = NULL;
|
|
Packit Service |
4684c1 |
const char **x509_keyfile = NULL;
|
|
Packit Service |
4684c1 |
const char **x509_certfile = NULL;
|
|
Packit Service |
4684c1 |
unsigned x509_certfile_size = 0;
|
|
Packit Service |
4684c1 |
unsigned x509_keyfile_size = 0;
|
|
Packit Service |
4684c1 |
const char *x509_cafile = NULL;
|
|
Packit Service |
4684c1 |
const char *dh_params_file = NULL;
|
|
Packit Service |
4684c1 |
const char *x509_crlfile = NULL;
|
|
Packit Service |
4684c1 |
const char *priorities = NULL;
|
|
Packit Service |
4684c1 |
const char **rawpk_keyfile = NULL;
|
|
Packit Service |
4684c1 |
const char **rawpk_file = NULL;
|
|
Packit Service |
4684c1 |
unsigned rawpk_keyfile_size = 0;
|
|
Packit Service |
4684c1 |
unsigned rawpk_file_size = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char **ocsp_responses = NULL;
|
|
Packit Service |
4684c1 |
unsigned ocsp_responses_size = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char *sni_hostname = NULL;
|
|
Packit Service |
4684c1 |
int sni_hostname_fatal = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char **alpn_protos = NULL;
|
|
Packit Service |
4684c1 |
unsigned alpn_protos_size = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_datum_t session_ticket_key;
|
|
Packit Service |
4684c1 |
gnutls_anti_replay_t anti_replay;
|
|
Packit Service |
4684c1 |
int record_max_size;
|
|
Packit Service |
4684c1 |
const char *http_data_file = NULL;
|
|
Packit Service |
4684c1 |
static void tcp_server(const char *name, int port);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* end of globals */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This is a sample TCP echo server.
|
|
Packit Service |
4684c1 |
* This will behave as an http server if any argument in the
|
|
Packit Service |
4684c1 |
* command line is present
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define SMALL_READ_TEST (2147483647)
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define GERR(ret) fprintf(stderr, "Error: %s\n", safe_strerror(ret))
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define HTTP_END "</BODY></HTML>\n\n"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define HTTP_UNIMPLEMENTED "\r\n<HTML><HEAD>\r\n<TITLE>501 Method Not Implemented</TITLE>\r\n</HEAD><BODY>\r\nMethod Not Implemented\r\n \r\n</BODY></HTML>\r\n"
|
|
Packit Service |
4684c1 |
#define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define HTTP_BEGIN HTTP_OK \
|
|
Packit Service |
4684c1 |
"\n" \
|
|
Packit Service |
4684c1 |
"<HTML><BODY>\n" \
|
|
Packit Service |
4684c1 |
"<CENTER>This is " \
|
|
Packit Service |
4684c1 |
"GnuTLS</CENTER>\n\n"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* These are global */
|
|
Packit Service |
4684c1 |
gnutls_srp_server_credentials_t srp_cred = NULL;
|
|
Packit Service |
4684c1 |
gnutls_psk_server_credentials_t psk_cred = NULL;
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ANON
|
|
Packit Service |
4684c1 |
gnutls_anon_server_credentials_t dh_cred = NULL;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
gnutls_certificate_credentials_t cert_cred = NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const int ssl_session_cache = 2048;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void wrap_db_init(void);
|
|
Packit Service |
4684c1 |
static void wrap_db_deinit(void);
|
|
Packit Service |
4684c1 |
static int wrap_db_store(void *dbf, gnutls_datum_t key,
|
|
Packit Service |
4684c1 |
gnutls_datum_t data);
|
|
Packit Service |
4684c1 |
static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key);
|
|
Packit Service |
4684c1 |
static int wrap_db_delete(void *dbf, gnutls_datum_t key);
|
|
Packit Service |
4684c1 |
static int anti_replay_db_add(void *dbf, time_t exp, const gnutls_datum_t *key,
|
|
Packit Service |
4684c1 |
const gnutls_datum_t *data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void cmd_parser(int argc, char **argv);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define HTTP_STATE_REQUEST 1
|
|
Packit Service |
4684c1 |
#define HTTP_STATE_RESPONSE 2
|
|
Packit Service |
4684c1 |
#define HTTP_STATE_CLOSING 3
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
LIST_TYPE_DECLARE(listener_item, char *http_request; char *http_response;
|
|
Packit Service |
4684c1 |
int request_length; int response_length;
|
|
Packit Service |
4684c1 |
int response_written; int http_state;
|
|
Packit Service |
4684c1 |
int listen_socket; int fd;
|
|
Packit Service |
4684c1 |
gnutls_session_t tls_session;
|
|
Packit Service |
4684c1 |
int handshake_ok;
|
|
Packit Service |
4684c1 |
int close_ok;
|
|
Packit Service |
4684c1 |
time_t start;
|
|
Packit Service |
4684c1 |
int earlydata_eof;
|
|
Packit Service |
4684c1 |
);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static const char *safe_strerror(int value)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const char *ret = gnutls_strerror(value);
|
|
Packit Service |
4684c1 |
if (ret == NULL)
|
|
Packit Service |
4684c1 |
ret = str_unknown;
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void listener_free(listener_item * j)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
free(j->http_request);
|
|
Packit Service |
4684c1 |
free(j->http_response);
|
|
Packit Service |
4684c1 |
if (j->fd >= 0) {
|
|
Packit Service |
4684c1 |
if (j->close_ok)
|
|
Packit Service |
4684c1 |
gnutls_bye(j->tls_session, GNUTLS_SHUT_WR);
|
|
Packit Service |
4684c1 |
shutdown(j->fd, 2);
|
|
Packit Service |
4684c1 |
close(j->fd);
|
|
Packit Service |
4684c1 |
gnutls_deinit(j->tls_session);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* we use primes up to 1024 in this server.
|
|
Packit Service |
4684c1 |
* otherwise we should add them here.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_dh_params_t dh_params = NULL;
|
|
Packit Service |
4684c1 |
gnutls_rsa_params_t rsa_params = NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int generate_dh_primes(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int prime_bits =
|
|
Packit Service |
4684c1 |
gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
|
|
Packit Service |
4684c1 |
GNUTLS_SEC_PARAM_MEDIUM);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_dh_params_init(&dh_params) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in dh parameter initialization\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Generate Diffie-Hellman parameters - for use with DHE
|
|
Packit Service |
4684c1 |
* kx algorithms. These should be discarded and regenerated
|
|
Packit Service |
4684c1 |
* once a week or once a month. Depends on the
|
|
Packit Service |
4684c1 |
* security requirements.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
printf
|
|
Packit Service |
4684c1 |
("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
|
|
Packit Service |
4684c1 |
prime_bits);
|
|
Packit Service |
4684c1 |
fflush(stdout);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_dh_params_generate2(dh_params, prime_bits) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in prime generation\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void read_dh_params(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char tmpdata[2048];
|
|
Packit Service |
4684c1 |
int size;
|
|
Packit Service |
4684c1 |
gnutls_datum_t params;
|
|
Packit Service |
4684c1 |
FILE *fp;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_dh_params_init(&dh_params) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in dh parameter initialization\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* read the params file
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
fp = fopen(dh_params_file, "r");
|
|
Packit Service |
4684c1 |
if (fp == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Could not open %s\n", dh_params_file);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
size = fread(tmpdata, 1, sizeof(tmpdata) - 1, fp);
|
|
Packit Service |
4684c1 |
tmpdata[size] = 0;
|
|
Packit Service |
4684c1 |
fclose(fp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
params.data = (unsigned char *) tmpdata;
|
|
Packit Service |
4684c1 |
params.size = size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
size =
|
|
Packit Service |
4684c1 |
gnutls_dh_params_import_pkcs3(dh_params, ¶ms,
|
|
Packit Service |
4684c1 |
GNUTLS_X509_FMT_PEM);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (size < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error parsing dh params: %s\n",
|
|
Packit Service |
4684c1 |
safe_strerror(size));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
printf("Read Diffie-Hellman parameters.\n");
|
|
Packit Service |
4684c1 |
fflush(stdout);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
get_params(gnutls_session_t session, gnutls_params_type_t type,
|
|
Packit Service |
4684c1 |
gnutls_params_st * st)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (type == GNUTLS_PARAMS_DH) {
|
|
Packit Service |
4684c1 |
if (dh_params == NULL)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
st->params.dh = dh_params;
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
st->type = type;
|
|
Packit Service |
4684c1 |
st->deinit = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
LIST_DECLARE_INIT(listener_list, listener_item, listener_free);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int cert_verify_callback(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
listener_item * j = gnutls_session_get_ptr(session);
|
|
Packit Service |
4684c1 |
unsigned int size;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_auth_get_type(session) == GNUTLS_CRD_CERTIFICATE) {
|
|
Packit Service |
4684c1 |
if (!require_cert && gnutls_certificate_get_peers(session, &size) == NULL)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ENABLED_OPT(VERIFY_CLIENT_CERT)) {
|
|
Packit Service |
4684c1 |
if (cert_verify(session, NULL, NULL) == 0) {
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
|
|
Packit Service |
4684c1 |
} while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
printf("- Peer's certificate was NOT verified.\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* callback used to verify if the host name advertised in client hello matches
|
|
Packit Service |
4684c1 |
* the one configured in server
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
post_client_hello(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
/* DNS names (only type supported) may be at most 256 byte long */
|
|
Packit Service |
4684c1 |
char *name;
|
|
Packit Service |
4684c1 |
size_t len = 256;
|
|
Packit Service |
4684c1 |
unsigned int type;
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
name = malloc(len);
|
|
Packit Service |
4684c1 |
if (name == NULL)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i=0; ; ) {
|
|
Packit Service |
4684c1 |
ret = gnutls_server_name_get(session, name, &len, &type, i);
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
|
|
Packit Service |
4684c1 |
char *new_name;
|
|
Packit Service |
4684c1 |
new_name = realloc(name, len);
|
|
Packit Service |
4684c1 |
if (new_name == NULL) {
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
4684c1 |
goto end;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
name = new_name;
|
|
Packit Service |
4684c1 |
continue; /* retry call with same index */
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* check if it is the last entry in list */
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
i++;
|
|
Packit Service |
4684c1 |
if (ret != GNUTLS_E_SUCCESS)
|
|
Packit Service |
4684c1 |
goto end;
|
|
Packit Service |
4684c1 |
/* unknown types need to be ignored */
|
|
Packit Service |
4684c1 |
if (type != GNUTLS_NAME_DNS)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (strlen(sni_hostname) != len)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
/* API guarantees that the name of type DNS will be null terminated */
|
|
Packit Service |
4684c1 |
if (!strncmp(name, sni_hostname, len)) {
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_SUCCESS;
|
|
Packit Service |
4684c1 |
goto end;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
};
|
|
Packit Service |
4684c1 |
/* when there is no extension, we can't send the extension specific alert */
|
|
Packit Service |
4684c1 |
if (i == 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Warning: client did not include SNI extension, using default host\n");
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_SUCCESS;
|
|
Packit Service |
4684c1 |
goto end;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (sni_hostname_fatal == 1) {
|
|
Packit Service |
4684c1 |
/* abort the connection, propagate error up the stack */
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_UNRECOGNIZED_NAME;
|
|
Packit Service |
4684c1 |
goto end;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Warning: client provided unrecognized host name\n");
|
|
Packit Service |
4684c1 |
/* since we just want to send an alert, not abort the connection, we
|
|
Packit Service |
4684c1 |
* need to send it ourselves
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_alert_send(session,
|
|
Packit Service |
4684c1 |
GNUTLS_AL_WARNING,
|
|
Packit Service |
4684c1 |
GNUTLS_A_UNRECOGNIZED_NAME);
|
|
Packit Service |
4684c1 |
} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* continue handshake, fall through */
|
|
Packit Service |
4684c1 |
end:
|
|
Packit Service |
4684c1 |
free(name);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define MAX_ALPN_PROTOCOLS 16
|
|
Packit Service |
4684c1 |
gnutls_session_t initialize_session(int dtls)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_session_t session;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned i;
|
|
Packit Service |
4684c1 |
const char *err;
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ALPN
|
|
Packit Service |
4684c1 |
gnutls_datum_t alpn[MAX_ALPN_PROTOCOLS];
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
unsigned alpn_size;
|
|
Packit Service |
4684c1 |
unsigned flags = GNUTLS_SERVER | GNUTLS_POST_HANDSHAKE_AUTH | GNUTLS_ENABLE_RAWPK;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (dtls)
|
|
Packit Service |
4684c1 |
flags |= GNUTLS_DATAGRAM;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (earlydata)
|
|
Packit Service |
4684c1 |
flags |= GNUTLS_ENABLE_EARLY_DATA;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_init(&session, flags);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* allow the use of private ciphersuites.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
gnutls_handshake_set_private_extensions(session, 1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_handshake_set_timeout(session,
|
|
Packit Service |
4684c1 |
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (nodb == 0) {
|
|
Packit Service |
4684c1 |
gnutls_db_set_retrieve_function(session, wrap_db_fetch);
|
|
Packit Service |
4684c1 |
gnutls_db_set_remove_function(session, wrap_db_delete);
|
|
Packit Service |
4684c1 |
gnutls_db_set_store_function(session, wrap_db_store);
|
|
Packit Service |
4684c1 |
gnutls_db_set_ptr(session, NULL);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (noticket == 0)
|
|
Packit Service |
4684c1 |
gnutls_session_ticket_enable_server(session,
|
|
Packit Service |
4684c1 |
&session_ticket_key);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (earlydata) {
|
|
Packit Service |
4684c1 |
gnutls_anti_replay_enable(session, anti_replay);
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(MAXEARLYDATA)) {
|
|
Packit Service |
4684c1 |
ret = gnutls_record_set_max_early_data_size(session, OPT_VALUE_MAXEARLYDATA);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Could not set max early data size: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (sni_hostname != NULL)
|
|
Packit Service |
4684c1 |
gnutls_handshake_set_post_client_hello_function(session,
|
|
Packit Service |
4684c1 |
&post_client_hello);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (priorities == NULL) {
|
|
Packit Service |
4684c1 |
ret = gnutls_set_default_priority(session);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Could not set default policy: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
ret = gnutls_priority_set_direct(session, priorities, &err;;
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Syntax error at: %s\n", err);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef ENABLE_ALPN
|
|
Packit Service |
4684c1 |
if (alpn_protos_size != 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "ALPN is not supported\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
alpn_size = MIN(MAX_ALPN_PROTOCOLS,alpn_protos_size);
|
|
Packit Service |
4684c1 |
for (i=0;i
|
|
Packit Service |
4684c1 |
alpn[i].data = (void*)alpn_protos[i];
|
|
Packit Service |
4684c1 |
alpn[i].size = strlen(alpn_protos[i]);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_alpn_set_protocols(session, alpn, alpn_size, HAVE_OPT(ALPN_FATAL)?GNUTLS_ALPN_MANDATORY:0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error setting ALPN protocols: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ANON
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_ANON, dh_cred);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (srp_cred != NULL)
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (psk_cred != NULL)
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_PSK, psk_cred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (cert_cred != NULL) {
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_verify_function(cert_cred,
|
|
Packit Service |
4684c1 |
cert_verify_callback);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
|
|
Packit Service |
4684c1 |
cert_cred);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (disable_client_cert)
|
|
Packit Service |
4684c1 |
gnutls_certificate_server_set_request(session,
|
|
Packit Service |
4684c1 |
GNUTLS_CERT_IGNORE);
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
if (require_cert)
|
|
Packit Service |
4684c1 |
gnutls_certificate_server_set_request(session,
|
|
Packit Service |
4684c1 |
GNUTLS_CERT_REQUIRE);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
gnutls_certificate_server_set_request(session,
|
|
Packit Service |
4684c1 |
GNUTLS_CERT_REQUEST);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* use the record size limit extension */
|
|
Packit Service |
4684c1 |
if (record_max_size > 0) {
|
|
Packit Service |
4684c1 |
if (gnutls_record_set_max_recv_size(session, record_max_size) <
|
|
Packit Service |
4684c1 |
0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Cannot set the maximum record receive size to %d.\n",
|
|
Packit Service |
4684c1 |
record_max_size);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(HEARTBEAT))
|
|
Packit Service |
4684c1 |
gnutls_heartbeat_enable(session,
|
|
Packit Service |
4684c1 |
GNUTLS_HB_PEER_ALLOWED_TO_SEND);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_DTLS_SRTP
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SRTP_PROFILES)) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_srtp_set_profile_direct(session,
|
|
Packit Service |
4684c1 |
OPT_ARG(SRTP_PROFILES),
|
|
Packit Service |
4684c1 |
&err;;
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_INVALID_REQUEST)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Syntax error at: %s\n", err);
|
|
Packit Service |
4684c1 |
else if (ret != 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in profiles: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
else fprintf(stderr,"DTLS profile set to %s\n",
|
|
Packit Service |
4684c1 |
OPT_ARG(SRTP_PROFILES));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret != 0) exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return session;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <gnutls/x509.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static const char DEFAULT_DATA[] =
|
|
Packit Service |
4684c1 |
"This is the default message reported by the GnuTLS implementation. "
|
|
Packit Service |
4684c1 |
"For more information please visit "
|
|
Packit Service |
4684c1 |
"https://www.gnutls.org/.";
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Creates html with the current session information.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
#define tmp_buffer &http_buffer[strlen(http_buffer)]
|
|
Packit Service |
4684c1 |
#define tmp_buffer_size len-strlen(http_buffer)
|
|
Packit Service |
4684c1 |
static char *peer_print_info(gnutls_session_t session, int *ret_length,
|
|
Packit Service |
4684c1 |
const char *header)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const char *tmp;
|
|
Packit Service |
4684c1 |
unsigned char sesid[32];
|
|
Packit Service |
4684c1 |
size_t i, sesid_size;
|
|
Packit Service |
4684c1 |
char *http_buffer, *desc;
|
|
Packit Service |
4684c1 |
gnutls_kx_algorithm_t kx_alg;
|
|
Packit Service |
4684c1 |
size_t len = 20 * 1024 + strlen(header);
|
|
Packit Service |
4684c1 |
char *crtinfo = NULL, *crtinfo_old = NULL;
|
|
Packit Service |
4684c1 |
gnutls_protocol_t version;
|
|
Packit Service |
4684c1 |
size_t ncrtinfo = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verbose == 0) {
|
|
Packit Service |
4684c1 |
http_buffer = malloc(len);
|
|
Packit Service |
4684c1 |
if (http_buffer == NULL)
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
strcpy(http_buffer, HTTP_BEGIN);
|
|
Packit Service |
4684c1 |
strcpy(&http_buffer[sizeof(HTTP_BEGIN) - 1], DEFAULT_DATA);
|
|
Packit Service |
4684c1 |
strcpy(&http_buffer
|
|
Packit Service |
4684c1 |
[sizeof(HTTP_BEGIN) + sizeof(DEFAULT_DATA) - 2],
|
|
Packit Service |
4684c1 |
HTTP_END);
|
|
Packit Service |
4684c1 |
*ret_length =
|
|
Packit Service |
4684c1 |
sizeof(DEFAULT_DATA) + sizeof(HTTP_BEGIN) +
|
|
Packit Service |
4684c1 |
sizeof(HTTP_END) - 3;
|
|
Packit Service |
4684c1 |
return http_buffer;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT) == GNUTLS_CRT_X509) {
|
|
Packit Service |
4684c1 |
const gnutls_datum_t *cert_list;
|
|
Packit Service |
4684c1 |
unsigned int cert_list_size = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cert_list =
|
|
Packit Service |
4684c1 |
gnutls_certificate_get_peers(session, &cert_list_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < cert_list_size; i++) {
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t cert = NULL;
|
|
Packit Service |
4684c1 |
gnutls_datum_t info;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_x509_crt_init(&cert) == 0 &&
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_import(cert, &cert_list[i],
|
|
Packit Service |
4684c1 |
GNUTLS_X509_FMT_DER) ==
|
|
Packit Service |
4684c1 |
0
|
|
Packit Service |
4684c1 |
&& gnutls_x509_crt_print(cert,
|
|
Packit Service |
4684c1 |
GNUTLS_CRT_PRINT_FULL,
|
|
Packit Service |
4684c1 |
&info) == 0) {
|
|
Packit Service |
4684c1 |
const char *post = "";
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
crtinfo_old = crtinfo;
|
|
Packit Service |
4684c1 |
crtinfo =
|
|
Packit Service |
4684c1 |
realloc(crtinfo,
|
|
Packit Service |
4684c1 |
ncrtinfo + info.size +
|
|
Packit Service |
4684c1 |
strlen(post) + 1);
|
|
Packit Service |
4684c1 |
if (crtinfo == NULL) {
|
|
Packit Service |
4684c1 |
free(crtinfo_old);
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
memcpy(crtinfo + ncrtinfo, info.data,
|
|
Packit Service |
4684c1 |
info.size);
|
|
Packit Service |
4684c1 |
ncrtinfo += info.size;
|
|
Packit Service |
4684c1 |
memcpy(crtinfo + ncrtinfo, post,
|
|
Packit Service |
4684c1 |
strlen(post));
|
|
Packit Service |
4684c1 |
ncrtinfo += strlen(post);
|
|
Packit Service |
4684c1 |
crtinfo[ncrtinfo] = '\0';
|
|
Packit Service |
4684c1 |
gnutls_free(info.data);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(cert);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
http_buffer = malloc(len);
|
|
Packit Service |
4684c1 |
if (http_buffer == NULL) {
|
|
Packit Service |
4684c1 |
free(crtinfo);
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
strcpy(http_buffer, HTTP_BEGIN);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
version = gnutls_protocol_get_version(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* print session_id */
|
|
Packit Service |
4684c1 |
sesid_size = sizeof(sesid);
|
|
Packit Service |
4684c1 |
gnutls_session_get_id(session, sesid, &sesid_size);
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size, "\nSession ID: ");
|
|
Packit Service |
4684c1 |
for (i = 0; i < sesid_size; i++)
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size, "\n");
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"If your browser supports session resumption, then you should see the "
|
|
Packit Service |
4684c1 |
"same session ID, when you press the reload button.\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Here unlike print_info() we use the kx algorithm to distinguish
|
|
Packit Service |
4684c1 |
* the functions to call.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char dns[256];
|
|
Packit Service |
4684c1 |
size_t dns_size = sizeof(dns);
|
|
Packit Service |
4684c1 |
unsigned int type;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_server_name_get
|
|
Packit Service |
4684c1 |
(session, dns, &dns_size, &type, 0) == 0) {
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"\nServer Name: %s \n", dns);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
kx_alg = gnutls_kx_get(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* print srp specific data */
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_SRP
|
|
Packit Service |
4684c1 |
if (kx_alg == GNUTLS_KX_SRP) {
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Connected as user '%s'. \n",
|
|
Packit Service |
4684c1 |
gnutls_srp_server_get_username(session));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PSK
|
|
Packit Service |
4684c1 |
if (kx_alg == GNUTLS_KX_PSK && gnutls_psk_server_get_username(session)) {
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Connected as user '%s'. \n",
|
|
Packit Service |
4684c1 |
gnutls_psk_server_get_username(session));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* print session information */
|
|
Packit Service |
4684c1 |
strcat(http_buffer, "\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
tmp =
|
|
Packit Service |
4684c1 |
gnutls_protocol_get_name(version);
|
|
Packit Service |
4684c1 |
if (tmp == NULL)
|
|
Packit Service |
4684c1 |
tmp = str_unknown;
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"\n",
|
|
Packit Service |
4684c1 |
tmp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
desc = gnutls_session_get_desc(session);
|
|
Packit Service |
4684c1 |
if (desc) {
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Description:%s\n",
|
|
Packit Service |
4684c1 |
desc);
|
|
Packit Service |
4684c1 |
gnutls_free(desc);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_auth_get_type(session) == GNUTLS_CRD_CERTIFICATE &&
|
|
Packit Service |
4684c1 |
gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT) != GNUTLS_CRT_X509) {
|
|
Packit Service |
4684c1 |
tmp =
|
|
Packit Service |
4684c1 |
gnutls_certificate_type_get_name
|
|
Packit Service |
4684c1 |
(gnutls_certificate_type_get2(session, GNUTLS_CTYPE_CLIENT));
|
|
Packit Service |
4684c1 |
if (tmp == NULL)
|
|
Packit Service |
4684c1 |
tmp = str_unknown;
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Certificate Type:%s\n",
|
|
Packit Service |
4684c1 |
tmp);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (version < GNUTLS_TLS1_3) {
|
|
Packit Service |
4684c1 |
tmp = gnutls_kx_get_name(kx_alg);
|
|
Packit Service |
4684c1 |
if (tmp == NULL)
|
|
Packit Service |
4684c1 |
tmp = str_unknown;
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Key Exchange:%s\n", tmp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ANON
|
|
Packit Service |
4684c1 |
if (kx_alg == GNUTLS_KX_ANON_DH) {
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
" Connect using anonymous DH (prime of %d bits) \n",
|
|
Packit Service |
4684c1 |
gnutls_dh_get_prime_bits(session));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
|
|
Packit Service |
4684c1 |
if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS) {
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Ephemeral DH using prime of %d bits. \n",
|
|
Packit Service |
4684c1 |
gnutls_dh_get_prime_bits(session));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
tmp = gnutls_compression_get_name(gnutls_compression_get(session));
|
|
Packit Service |
4684c1 |
if (tmp == NULL)
|
|
Packit Service |
4684c1 |
tmp = str_unknown;
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Compression%s\n", tmp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
tmp = gnutls_cipher_suite_get_name(kx_alg,
|
|
Packit Service |
4684c1 |
gnutls_cipher_get(session),
|
|
Packit Service |
4684c1 |
gnutls_mac_get(session));
|
|
Packit Service |
4684c1 |
if (tmp == NULL)
|
|
Packit Service |
4684c1 |
tmp = str_unknown;
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Ciphersuite%s\n",
|
|
Packit Service |
4684c1 |
tmp);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
tmp = gnutls_cipher_get_name(gnutls_cipher_get(session));
|
|
Packit Service |
4684c1 |
if (tmp == NULL)
|
|
Packit Service |
4684c1 |
tmp = str_unknown;
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"Cipher%s\n", tmp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
tmp = gnutls_mac_get_name(gnutls_mac_get(session));
|
|
Packit Service |
4684c1 |
if (tmp == NULL)
|
|
Packit Service |
4684c1 |
tmp = str_unknown;
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"MAC%s\n", tmp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (crtinfo) {
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"
%s\n \n", crtinfo);
|
|
Packit Service |
4684c1 |
free(crtinfo);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
snprintf(tmp_buffer, tmp_buffer_size,
|
|
Packit Service |
4684c1 |
"
Your HTTP header was: %s \n"
|
|
Packit Service |
4684c1 |
HTTP_END, header);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*ret_length = strlen(http_buffer);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return http_buffer;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static char *peer_print_data(gnutls_session_t session, int *ret_length)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t data;
|
|
Packit Service |
4684c1 |
char *http_buffer;
|
|
Packit Service |
4684c1 |
size_t len;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_load_file(http_data_file, &data);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
ret = asprintf(&http_buffer,
|
|
Packit Service |
4684c1 |
"HTTP/1.0 404 Not Found\r\n"
|
|
Packit Service |
4684c1 |
"Content-type: text/html\r\n"
|
|
Packit Service |
4684c1 |
"\r\n"
|
|
Packit Service |
4684c1 |
"<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
|
|
Packit Service |
4684c1 |
"<BODY>Couldn't read %s</BODY></HTML>\n\n",
|
|
Packit Service |
4684c1 |
http_data_file);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*ret_length = strlen(http_buffer);
|
|
Packit Service |
4684c1 |
return http_buffer;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = asprintf(&http_buffer,
|
|
Packit Service |
4684c1 |
"HTTP/1.0 200 OK\r\n"
|
|
Packit Service |
4684c1 |
"Content-Type: application/octet-stream\r\n"
|
|
Packit Service |
4684c1 |
"Content-Length: %u\r\n"
|
|
Packit Service |
4684c1 |
"\r\n",
|
|
Packit Service |
4684c1 |
data.size);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
len = ret;
|
|
Packit Service |
4684c1 |
http_buffer = realloc(http_buffer, len + data.size);
|
|
Packit Service |
4684c1 |
memcpy(&http_buffer[len], data.data, data.size);
|
|
Packit Service |
4684c1 |
gnutls_free(data.data);
|
|
Packit Service |
4684c1 |
*ret_length = len + data.size;
|
|
Packit Service |
4684c1 |
return http_buffer;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char *human_addr(const struct sockaddr *sa, socklen_t salen,
|
|
Packit Service |
4684c1 |
char *buf, size_t buflen)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const char *save_buf = buf;
|
|
Packit Service |
4684c1 |
size_t l;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!buf || !buflen)
|
|
Packit Service |
4684c1 |
return "(error)";
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*buf = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
switch (sa->sa_family) {
|
|
Packit Service |
4684c1 |
#if HAVE_IPV6
|
|
Packit Service |
4684c1 |
case AF_INET6:
|
|
Packit Service |
4684c1 |
snprintf(buf, buflen, "IPv6 ");
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
case AF_INET:
|
|
Packit Service |
4684c1 |
snprintf(buf, buflen, "IPv4 ");
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
l = 5;
|
|
Packit Service |
4684c1 |
buf += l;
|
|
Packit Service |
4684c1 |
buflen -= l;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) !=
|
|
Packit Service |
4684c1 |
0) {
|
|
Packit Service |
4684c1 |
return "(error)";
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
l = strlen(buf);
|
|
Packit Service |
4684c1 |
buf += l;
|
|
Packit Service |
4684c1 |
buflen -= l;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (buflen < 8)
|
|
Packit Service |
4684c1 |
return save_buf;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
strcat(buf, " port ");
|
|
Packit Service |
4684c1 |
buf += 6;
|
|
Packit Service |
4684c1 |
buflen -= 6;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) !=
|
|
Packit Service |
4684c1 |
0) {
|
|
Packit Service |
4684c1 |
snprintf(buf, buflen, "%s", " unknown");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return save_buf;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int wait_for_connection(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
listener_item *j;
|
|
Packit Service |
4684c1 |
fd_set rd, wr;
|
|
Packit Service |
4684c1 |
int n, sock = -1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
FD_ZERO(&rd);
|
|
Packit Service |
4684c1 |
FD_ZERO(&wr);
|
|
Packit Service |
4684c1 |
n = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
lloopstart(listener_list, j) {
|
|
Packit Service |
4684c1 |
if (j->listen_socket) {
|
|
Packit Service |
4684c1 |
FD_SET(j->fd, &rd);
|
|
Packit Service |
4684c1 |
n = MAX(n, j->fd);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
lloopend(listener_list, j);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* waiting part */
|
|
Packit Service |
4684c1 |
n = select(n + 1, &rd, &wr, NULL, NULL);
|
|
Packit Service |
4684c1 |
if (n == -1 && errno == EINTR)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
if (n < 0) {
|
|
Packit Service |
4684c1 |
perror("select()");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* find which one is ready */
|
|
Packit Service |
4684c1 |
lloopstart(listener_list, j) {
|
|
Packit Service |
4684c1 |
/* a new connection has arrived */
|
|
Packit Service |
4684c1 |
if (FD_ISSET(j->fd, &rd) && j->listen_socket) {
|
|
Packit Service |
4684c1 |
sock = j->fd;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
lloopend(listener_list, j);
|
|
Packit Service |
4684c1 |
return sock;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int listen_socket(const char *name, int listen_port, int socktype)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
struct addrinfo hints, *res, *ptr;
|
|
Packit Service |
4684c1 |
char portname[6];
|
|
Packit Service |
4684c1 |
int s = -1;
|
|
Packit Service |
4684c1 |
int yes;
|
|
Packit Service |
4684c1 |
listener_item *j = NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
snprintf(portname, sizeof(portname), "%d", listen_port);
|
|
Packit Service |
4684c1 |
memset(&hints, 0, sizeof(hints));
|
|
Packit Service |
4684c1 |
hints.ai_socktype = socktype;
|
|
Packit Service |
4684c1 |
hints.ai_flags = AI_PASSIVE
|
|
Packit Service |
4684c1 |
#ifdef AI_ADDRCONFIG
|
|
Packit Service |
4684c1 |
| AI_ADDRCONFIG
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((s = getaddrinfo(NULL, portname, &hints, &res)) != 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "getaddrinfo() failed: %s\n",
|
|
Packit Service |
4684c1 |
gai_strerror(s));
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
|
|
Packit Service |
4684c1 |
int news;
|
|
Packit Service |
4684c1 |
#ifndef HAVE_IPV6
|
|
Packit Service |
4684c1 |
if (ptr->ai_family != AF_INET)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Print what we are doing. */
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char topbuf[512];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fprintf(stderr, "%s listening on %s...",
|
|
Packit Service |
4684c1 |
name, human_addr(ptr->ai_addr,
|
|
Packit Service |
4684c1 |
ptr->ai_addrlen, topbuf,
|
|
Packit Service |
4684c1 |
sizeof(topbuf)));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((news = socket(ptr->ai_family, ptr->ai_socktype,
|
|
Packit Service |
4684c1 |
ptr->ai_protocol)) < 0) {
|
|
Packit Service |
4684c1 |
perror("socket() failed");
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
s = news; /* to not overwrite existing s from previous loops */
|
|
Packit Service |
4684c1 |
#if defined(HAVE_IPV6) && !defined(_WIN32)
|
|
Packit Service |
4684c1 |
if (ptr->ai_family == AF_INET6) {
|
|
Packit Service |
4684c1 |
yes = 1;
|
|
Packit Service |
4684c1 |
/* avoid listen on ipv6 addresses failing
|
|
Packit Service |
4684c1 |
* because already listening on ipv4 addresses: */
|
|
Packit Service |
4684c1 |
(void)setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
Packit Service |
4684c1 |
(const void *) &yes, sizeof(yes));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socktype == SOCK_STREAM) {
|
|
Packit Service |
4684c1 |
yes = 1;
|
|
Packit Service |
4684c1 |
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
|
Packit Service |
4684c1 |
(const void *) &yes,
|
|
Packit Service |
4684c1 |
sizeof(yes)) < 0) {
|
|
Packit Service |
4684c1 |
perror("setsockopt() failed");
|
|
Packit Service |
4684c1 |
close(s);
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
#if defined(IP_DONTFRAG)
|
|
Packit Service |
4684c1 |
yes = 1;
|
|
Packit Service |
4684c1 |
if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
|
|
Packit Service |
4684c1 |
(const void *) &yes,
|
|
Packit Service |
4684c1 |
sizeof(yes)) < 0)
|
|
Packit Service |
4684c1 |
perror("setsockopt(IP_DF) failed");
|
|
Packit Service |
4684c1 |
#elif defined(IP_MTU_DISCOVER)
|
|
Packit Service |
4684c1 |
yes = IP_PMTUDISC_DO;
|
|
Packit Service |
4684c1 |
if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
|
|
Packit Service |
4684c1 |
(const void *) &yes,
|
|
Packit Service |
4684c1 |
sizeof(yes)) < 0)
|
|
Packit Service |
4684c1 |
perror("setsockopt(IP_DF) failed");
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (bind(s, ptr->ai_addr, ptr->ai_addrlen) < 0) {
|
|
Packit Service |
4684c1 |
perror("bind() failed");
|
|
Packit Service |
4684c1 |
close(s);
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socktype == SOCK_STREAM) {
|
|
Packit Service |
4684c1 |
if (listen(s, 10) < 0) {
|
|
Packit Service |
4684c1 |
perror("listen() failed");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* new list entry for the connection */
|
|
Packit Service |
4684c1 |
lappend(listener_list);
|
|
Packit Service |
4684c1 |
j = listener_list.tail;
|
|
Packit Service |
4684c1 |
j->listen_socket = 1;
|
|
Packit Service |
4684c1 |
j->fd = s;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Complete earlier message. */
|
|
Packit Service |
4684c1 |
fprintf(stderr, "done\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
fflush(stderr);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
freeaddrinfo(res);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return s;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* strips \r\n from the end of the string
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static void strip(char *data)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
int len = strlen(data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < len; i++) {
|
|
Packit Service |
4684c1 |
if (data[i] == '\r' && data[i + 1] == '\n'
|
|
Packit Service |
4684c1 |
&& data[i + 2] == 0) {
|
|
Packit Service |
4684c1 |
data[i] = '\n';
|
|
Packit Service |
4684c1 |
data[i + 1] = 0;
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static unsigned
|
|
Packit Service |
4684c1 |
get_response(gnutls_session_t session, char *request,
|
|
Packit Service |
4684c1 |
char **response, int *response_length)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char *p, *h;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (http != 0) {
|
|
Packit Service |
4684c1 |
if (strncmp(request, "GET ", 4))
|
|
Packit Service |
4684c1 |
goto unimplemented;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!(h = strchr(request, '\n')))
|
|
Packit Service |
4684c1 |
goto unimplemented;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*h++ = '\0';
|
|
Packit Service |
4684c1 |
while (*h == '\r' || *h == '\n')
|
|
Packit Service |
4684c1 |
h++;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!(p = strchr(request + 4, ' ')))
|
|
Packit Service |
4684c1 |
goto unimplemented;
|
|
Packit Service |
4684c1 |
*p = '\0';
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (http != 0) {
|
|
Packit Service |
4684c1 |
if (http_data_file == NULL)
|
|
Packit Service |
4684c1 |
*response = peer_print_info(session, response_length, h);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
*response = peer_print_data(session, response_length);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
strip(request);
|
|
Packit Service |
4684c1 |
fprintf(stderr, "received cmd: %s\n", request);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = check_command(session, request, disable_client_cert);
|
|
Packit Service |
4684c1 |
if (ret > 0) {
|
|
Packit Service |
4684c1 |
*response = strdup("Successfully executed command\n");
|
|
Packit Service |
4684c1 |
if (*response == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Memory error\n");
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
*response_length = strlen(*response);
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
} else if (ret == 0) {
|
|
Packit Service |
4684c1 |
*response = strdup(request);
|
|
Packit Service |
4684c1 |
if (*response == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Memory error\n");
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
*response_length = strlen(*response);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
*response = NULL;
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_alert_send_appropriate(session, ret);
|
|
Packit Service |
4684c1 |
} while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
unimplemented:
|
|
Packit Service |
4684c1 |
*response = strdup(HTTP_UNIMPLEMENTED);
|
|
Packit Service |
4684c1 |
if (*response == NULL)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
*response_length = ((*response) ? strlen(*response) : 0);
|
|
Packit Service |
4684c1 |
return 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void terminate(int sig) __attribute__ ((__noreturn__));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void terminate(int sig)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Exiting via signal %d\n", sig);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void check_alert(gnutls_session_t session, int ret)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
|
|
Packit Service |
4684c1 |
|| ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
|
|
Packit Service |
4684c1 |
int last_alert = gnutls_alert_get(session);
|
|
Packit Service |
4684c1 |
if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
|
|
Packit Service |
4684c1 |
ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
|
|
Packit Service |
4684c1 |
printf
|
|
Packit Service |
4684c1 |
("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
printf("* Received alert '%d': %s.\n", last_alert,
|
|
Packit Service |
4684c1 |
gnutls_alert_get_name(last_alert));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void tls_log_func(int level, const char *str)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
fprintf(stderr, "|<%d>| %s", level, str);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void tls_audit_log_func(gnutls_session_t session, const char *str)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
fprintf(stderr, "|<%p>| %s", session, str);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int main(int argc, char **argv)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret, mtu, port;
|
|
Packit Service |
4684c1 |
char name[256];
|
|
Packit Service |
4684c1 |
int cert_set = 0;
|
|
Packit Service |
4684c1 |
unsigned use_static_dh_params = 0;
|
|
Packit Service |
4684c1 |
unsigned i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cmd_parser(argc, argv);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
signal(SIGHUP, SIG_IGN);
|
|
Packit Service |
4684c1 |
signal(SIGTERM, terminate);
|
|
Packit Service |
4684c1 |
if (signal(SIGINT, terminate) == SIG_IGN)
|
|
Packit Service |
4684c1 |
signal(SIGINT, SIG_IGN); /* e.g. background process */
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sockets_init();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (nodb == 0)
|
|
Packit Service |
4684c1 |
wrap_db_init();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(UDP))
|
|
Packit Service |
4684c1 |
strcpy(name, "UDP ");
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
name[0] = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (http == 1) {
|
|
Packit Service |
4684c1 |
strcat(name, "HTTP Server");
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
strcat(name, "Echo Server");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_global_set_log_function(tls_log_func);
|
|
Packit Service |
4684c1 |
gnutls_global_set_audit_log_function(tls_audit_log_func);
|
|
Packit Service |
4684c1 |
gnutls_global_set_log_level(debug);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((ret = gnutls_global_init()) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PKCS11
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PROVIDER)) {
|
|
Packit Service |
4684c1 |
ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "pkcs11_init: %s",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_pkcs11_add_provider(OPT_ARG(PROVIDER),
|
|
Packit Service |
4684c1 |
NULL);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "pkcs11_add_provider: %s",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
pkcs11_common(NULL);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Note that servers must generate parameters for
|
|
Packit Service |
4684c1 |
* Diffie-Hellman. See gnutls_dh_params_generate(), and
|
|
Packit Service |
4684c1 |
* gnutls_dh_params_set().
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
if (generate != 0) {
|
|
Packit Service |
4684c1 |
generate_dh_primes();
|
|
Packit Service |
4684c1 |
} else if (dh_params_file) {
|
|
Packit Service |
4684c1 |
read_dh_params();
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
use_static_dh_params = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (gnutls_certificate_allocate_credentials(&cert_cred) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "memory error\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* X509 credentials */
|
|
Packit Service |
4684c1 |
if (x509_cafile != NULL) {
|
|
Packit Service |
4684c1 |
if ((ret = gnutls_certificate_set_x509_trust_file
|
|
Packit Service |
4684c1 |
(cert_cred, x509_cafile, x509ctype)) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error reading '%s'\n",
|
|
Packit Service |
4684c1 |
x509_cafile);
|
|
Packit Service |
4684c1 |
GERR(ret);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
printf("Processed %d CA certificate(s).\n", ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (x509_crlfile != NULL) {
|
|
Packit Service |
4684c1 |
if ((ret = gnutls_certificate_set_x509_crl_file
|
|
Packit Service |
4684c1 |
(cert_cred, x509_crlfile, x509ctype)) < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error reading '%s'\n",
|
|
Packit Service |
4684c1 |
x509_crlfile);
|
|
Packit Service |
4684c1 |
GERR(ret);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
printf("Processed %d CRL(s).\n", ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (x509_certfile_size > 0 && x509_keyfile_size > 0) {
|
|
Packit Service |
4684c1 |
for (i = 0; i < x509_certfile_size; i++) {
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_x509_key_file
|
|
Packit Service |
4684c1 |
(cert_cred, x509_certfile[i], x509_keyfile[i], x509ctype);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error reading '%s' or '%s'\n",
|
|
Packit Service |
4684c1 |
x509_certfile[i], x509_keyfile[i]);
|
|
Packit Service |
4684c1 |
GERR(ret);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
cert_set = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Raw public-key credentials */
|
|
Packit Service |
4684c1 |
if (rawpk_file_size > 0 && rawpk_keyfile_size > 0) {
|
|
Packit Service |
4684c1 |
for (i = 0; i < rawpk_keyfile_size; i++) {
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_rawpk_key_file(cert_cred, rawpk_file[i],
|
|
Packit Service |
4684c1 |
rawpk_keyfile[i],
|
|
Packit Service |
4684c1 |
x509ctype,
|
|
Packit Service |
4684c1 |
NULL, 0, NULL, 0,
|
|
Packit Service |
4684c1 |
0, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error reading '%s' or '%s'\n",
|
|
Packit Service |
4684c1 |
rawpk_file[i], rawpk_keyfile[i]);
|
|
Packit Service |
4684c1 |
GERR(ret);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
cert_set = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (cert_set == 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Warning: no private key and certificate pairs were set.\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef ENABLE_OCSP
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(IGNORE_OCSP_RESPONSE_ERRORS) || ocsp_responses_size != 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "OCSP is not supported!\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
/* OCSP status-request TLS extension */
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(IGNORE_OCSP_RESPONSE_ERRORS))
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_flags(cert_cred, GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < ocsp_responses_size; i++ ) {
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_ocsp_status_request_file
|
|
Packit Service |
4684c1 |
(cert_cred, ocsp_responses[i], 0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Cannot set OCSP status request file: %s: %s\n",
|
|
Packit Service |
4684c1 |
ocsp_responses[i],
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (use_static_dh_params) {
|
|
Packit Service |
4684c1 |
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
|
|
Packit Service |
4684c1 |
ret = gnutls_certificate_set_known_dh_params(cert_cred, GNUTLS_SEC_PARAM_MEDIUM);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error while setting DH parameters: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#else
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Setting DH parameters is not supported\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
gnutls_certificate_set_params_function(cert_cred, get_params);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* this is a password file (created with the included srpcrypt utility)
|
|
Packit Service |
4684c1 |
* Read README.crypt prior to using SRP.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_SRP
|
|
Packit Service |
4684c1 |
if (srp_passwd != NULL) {
|
|
Packit Service |
4684c1 |
gnutls_srp_allocate_server_credentials(&srp_cred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((ret =
|
|
Packit Service |
4684c1 |
gnutls_srp_set_server_credentials_file(srp_cred,
|
|
Packit Service |
4684c1 |
srp_passwd,
|
|
Packit Service |
4684c1 |
srp_passwd_conf))
|
|
Packit Service |
4684c1 |
< 0) {
|
|
Packit Service |
4684c1 |
/* only exit is this function is not disabled
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error while setting SRP parameters\n");
|
|
Packit Service |
4684c1 |
GERR(ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* this is a password file
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PSK
|
|
Packit Service |
4684c1 |
if (psk_passwd != NULL) {
|
|
Packit Service |
4684c1 |
gnutls_psk_allocate_server_credentials(&psk_cred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((ret =
|
|
Packit Service |
4684c1 |
gnutls_psk_set_server_credentials_file(psk_cred,
|
|
Packit Service |
4684c1 |
psk_passwd)) <
|
|
Packit Service |
4684c1 |
0) {
|
|
Packit Service |
4684c1 |
/* only exit is this function is not disabled
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error while setting PSK parameters\n");
|
|
Packit Service |
4684c1 |
GERR(ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PSKHINT)) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_psk_set_server_credentials_hint
|
|
Packit Service |
4684c1 |
(psk_cred, OPT_ARG(PSKHINT));
|
|
Packit Service |
4684c1 |
if (ret) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error setting PSK identity hint.\n");
|
|
Packit Service |
4684c1 |
GERR(ret);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (use_static_dh_params) {
|
|
Packit Service |
4684c1 |
ret = gnutls_psk_set_server_known_dh_params(psk_cred, GNUTLS_SEC_PARAM_MEDIUM);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error while setting DH parameters: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
gnutls_psk_set_server_params_function(psk_cred,
|
|
Packit Service |
4684c1 |
get_params);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ANON
|
|
Packit Service |
4684c1 |
gnutls_anon_allocate_server_credentials(&dh_cred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (use_static_dh_params) {
|
|
Packit Service |
4684c1 |
ret = gnutls_anon_set_server_known_dh_params(dh_cred, GNUTLS_SEC_PARAM_MEDIUM);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error while setting DH parameters: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
gnutls_anon_set_server_params_function(dh_cred, get_params);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (noticket == 0)
|
|
Packit Service |
4684c1 |
gnutls_session_ticket_key_generate(&session_ticket_key);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (earlydata) {
|
|
Packit Service |
4684c1 |
ret = gnutls_anti_replay_init(&anti_replay);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error while initializing anti-replay: %s\n", gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
gnutls_anti_replay_set_add_function(anti_replay, anti_replay_db_add);
|
|
Packit Service |
4684c1 |
gnutls_anti_replay_set_ptr(anti_replay, NULL);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(MTU))
|
|
Packit Service |
4684c1 |
mtu = OPT_VALUE_MTU;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
mtu = 1300;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PORT))
|
|
Packit Service |
4684c1 |
port = OPT_VALUE_PORT;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
port = 5556;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(UDP))
|
|
Packit Service |
4684c1 |
udp_server(name, port, mtu);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
tcp_server(name, port);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void retry_handshake(listener_item *j)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int r, ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
r = gnutls_handshake(j->tls_session);
|
|
Packit Service |
4684c1 |
if (r < 0 && gnutls_error_is_fatal(r) == 0) {
|
|
Packit Service |
4684c1 |
check_alert(j->tls_session, r);
|
|
Packit Service |
4684c1 |
/* nothing */
|
|
Packit Service |
4684c1 |
} else if (r < 0) {
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
check_alert(j->tls_session, r);
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in handshake: %s\n", gnutls_strerror(r));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_alert_send_appropriate(j->tls_session, r);
|
|
Packit Service |
4684c1 |
} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
|
|
Packit Service |
4684c1 |
j->close_ok = 0;
|
|
Packit Service |
4684c1 |
} else if (r == 0) {
|
|
Packit Service |
4684c1 |
if (gnutls_session_is_resumed(j->tls_session) != 0 && verbose != 0)
|
|
Packit Service |
4684c1 |
printf("*** This is a resumed session\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verbose != 0) {
|
|
Packit Service |
4684c1 |
#if 0
|
|
Packit Service |
4684c1 |
printf("- connection from %s\n",
|
|
Packit Service |
4684c1 |
human_addr((struct sockaddr *)
|
|
Packit Service |
4684c1 |
&client_address,
|
|
Packit Service |
4684c1 |
calen,
|
|
Packit Service |
4684c1 |
topbuf,
|
|
Packit Service |
4684c1 |
sizeof(topbuf)));
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
print_info(j->tls_session, verbose, verbose);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(KEYMATEXPORT))
|
|
Packit Service |
4684c1 |
print_key_material(j->tls_session,
|
|
Packit Service |
4684c1 |
OPT_ARG(KEYMATEXPORT),
|
|
Packit Service |
4684c1 |
HAVE_OPT(KEYMATEXPORTSIZE) ?
|
|
Packit Service |
4684c1 |
OPT_VALUE_KEYMATEXPORTSIZE :
|
|
Packit Service |
4684c1 |
20);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
j->close_ok = 1;
|
|
Packit Service |
4684c1 |
j->handshake_ok = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void try_rehandshake(listener_item *j)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int r, ret;
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** Received hello message\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
r = gnutls_handshake(j->tls_session);
|
|
Packit Service |
4684c1 |
} while (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (r < 0) {
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_alert_send_appropriate(j->tls_session, r);
|
|
Packit Service |
4684c1 |
} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Error in rehandshake: %s\n", gnutls_strerror(r));
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
j->close_ok = 1;
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_REQUEST;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void tcp_server(const char *name, int port)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int n, s;
|
|
Packit Service |
4684c1 |
char topbuf[512];
|
|
Packit Service |
4684c1 |
int accept_fd;
|
|
Packit Service |
4684c1 |
struct sockaddr_storage client_address;
|
|
Packit Service |
4684c1 |
socklen_t calen;
|
|
Packit Service |
4684c1 |
struct timeval tv;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
s = listen_socket(name, port, SOCK_STREAM);
|
|
Packit Service |
4684c1 |
if (s < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (;;) {
|
|
Packit Service |
4684c1 |
listener_item *j;
|
|
Packit Service |
4684c1 |
fd_set rd, wr;
|
|
Packit Service |
4684c1 |
time_t now = time(0);
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
int val;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
FD_ZERO(&rd);
|
|
Packit Service |
4684c1 |
FD_ZERO(&wr);
|
|
Packit Service |
4684c1 |
n = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* flag which connections we are reading or writing to within the fd sets */
|
|
Packit Service |
4684c1 |
lloopstart(listener_list, j) {
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef _WIN32
|
|
Packit Service |
4684c1 |
val = fcntl(j->fd, F_GETFL, 0);
|
|
Packit Service |
4684c1 |
if ((val == -1)
|
|
Packit Service |
4684c1 |
|| (fcntl(j->fd, F_SETFL, val | O_NONBLOCK) <
|
|
Packit Service |
4684c1 |
0)) {
|
|
Packit Service |
4684c1 |
perror("fcntl()");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
if (j->start != 0 && now - j->start > 30) {
|
|
Packit Service |
4684c1 |
if (verbose != 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Scheduling inactive connection for close\n");
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (j->listen_socket) {
|
|
Packit Service |
4684c1 |
FD_SET(j->fd, &rd);
|
|
Packit Service |
4684c1 |
n = MAX(n, j->fd);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (j->http_state == HTTP_STATE_REQUEST) {
|
|
Packit Service |
4684c1 |
FD_SET(j->fd, &rd);
|
|
Packit Service |
4684c1 |
n = MAX(n, j->fd);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (j->http_state == HTTP_STATE_RESPONSE) {
|
|
Packit Service |
4684c1 |
FD_SET(j->fd, &wr);
|
|
Packit Service |
4684c1 |
n = MAX(n, j->fd);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
lloopend(listener_list, j);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* core operation */
|
|
Packit Service |
4684c1 |
tv.tv_sec = 10;
|
|
Packit Service |
4684c1 |
tv.tv_usec = 0;
|
|
Packit Service |
4684c1 |
n = select(n + 1, &rd, &wr, NULL, &tv;;
|
|
Packit Service |
4684c1 |
if (n == -1 && errno == EINTR)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
if (n < 0) {
|
|
Packit Service |
4684c1 |
perror("select()");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* read or write to each connection as indicated by select()'s return argument */
|
|
Packit Service |
4684c1 |
lloopstart(listener_list, j) {
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* a new connection has arrived */
|
|
Packit Service |
4684c1 |
if (FD_ISSET(j->fd, &rd) && j->listen_socket) {
|
|
Packit Service |
4684c1 |
calen = sizeof(client_address);
|
|
Packit Service |
4684c1 |
memset(&client_address, 0, calen);
|
|
Packit Service |
4684c1 |
accept_fd =
|
|
Packit Service |
4684c1 |
accept(j->fd,
|
|
Packit Service |
4684c1 |
(struct sockaddr *)
|
|
Packit Service |
4684c1 |
&client_address, &calen);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (accept_fd < 0) {
|
|
Packit Service |
4684c1 |
perror("accept()");
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
char timebuf[SIMPLE_CTIME_BUF_SIZE];
|
|
Packit Service |
4684c1 |
time_t tt = time(0);
|
|
Packit Service |
4684c1 |
char *ctt;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* new list entry for the connection */
|
|
Packit Service |
4684c1 |
lappend(listener_list);
|
|
Packit Service |
4684c1 |
j = listener_list.tail;
|
|
Packit Service |
4684c1 |
j->http_request =
|
|
Packit Service |
4684c1 |
(char *) strdup("");
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_REQUEST;
|
|
Packit Service |
4684c1 |
j->fd = accept_fd;
|
|
Packit Service |
4684c1 |
j->start = tt;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
j->tls_session = initialize_session(0);
|
|
Packit Service |
4684c1 |
gnutls_session_set_ptr(j->tls_session, j);
|
|
Packit Service |
4684c1 |
gnutls_transport_set_int
|
|
Packit Service |
4684c1 |
(j->tls_session, accept_fd);
|
|
Packit Service |
4684c1 |
set_read_funcs(j->tls_session);
|
|
Packit Service |
4684c1 |
j->handshake_ok = 0;
|
|
Packit Service |
4684c1 |
j->close_ok = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verbose != 0) {
|
|
Packit Service |
4684c1 |
ctt = simple_ctime(&tt, timebuf);
|
|
Packit Service |
4684c1 |
ctt[strlen(ctt) - 1] = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
printf
|
|
Packit Service |
4684c1 |
("\n* Accepted connection from %s on %s\n",
|
|
Packit Service |
4684c1 |
human_addr((struct
|
|
Packit Service |
4684c1 |
sockaddr
|
|
Packit Service |
4684c1 |
*)
|
|
Packit Service |
4684c1 |
&client_address,
|
|
Packit Service |
4684c1 |
calen,
|
|
Packit Service |
4684c1 |
topbuf,
|
|
Packit Service |
4684c1 |
sizeof
|
|
Packit Service |
4684c1 |
(topbuf)),
|
|
Packit Service |
4684c1 |
ctt);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (FD_ISSET(j->fd, &rd) && !j->listen_socket) {
|
|
Packit Service |
4684c1 |
/* read partial GET request */
|
|
Packit Service |
4684c1 |
char buf[16*1024];
|
|
Packit Service |
4684c1 |
int r;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (j->handshake_ok == 0) {
|
|
Packit Service |
4684c1 |
retry_handshake(j);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (j->handshake_ok == 1) {
|
|
Packit Service |
4684c1 |
int earlydata_read = 0;
|
|
Packit Service |
4684c1 |
if (earlydata && !j->earlydata_eof) {
|
|
Packit Service |
4684c1 |
r = gnutls_record_recv_early_data(j->
|
|
Packit Service |
4684c1 |
tls_session,
|
|
Packit Service |
4684c1 |
buf,
|
|
Packit Service |
4684c1 |
MIN(sizeof(buf),
|
|
Packit Service |
4684c1 |
SMALL_READ_TEST));
|
|
Packit Service |
4684c1 |
if (r == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit Service |
4684c1 |
j->earlydata_eof = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (r == 0) {
|
|
Packit Service |
4684c1 |
earlydata_read = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (!earlydata_read) {
|
|
Packit Service |
4684c1 |
r = gnutls_record_recv(j->
|
|
Packit Service |
4684c1 |
tls_session,
|
|
Packit Service |
4684c1 |
buf,
|
|
Packit Service |
4684c1 |
MIN(sizeof(buf),
|
|
Packit Service |
4684c1 |
SMALL_READ_TEST));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
|
|
Packit Service |
4684c1 |
/* do nothing */
|
|
Packit Service |
4684c1 |
} else if (r <= 0) {
|
|
Packit Service |
4684c1 |
if (r == GNUTLS_E_HEARTBEAT_PING_RECEIVED) {
|
|
Packit Service |
4684c1 |
gnutls_heartbeat_pong(j->tls_session, 0);
|
|
Packit Service |
4684c1 |
} else if (r == GNUTLS_E_REHANDSHAKE) {
|
|
Packit Service |
4684c1 |
try_rehandshake(j);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
if (r < 0) {
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
check_alert(j->tls_session, r);
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error while receiving data\n");
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = gnutls_alert_send_appropriate(j->tls_session, r);
|
|
Packit Service |
4684c1 |
} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
|
|
Packit Service |
4684c1 |
GERR(r);
|
|
Packit Service |
4684c1 |
j->close_ok = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
j->http_request =
|
|
Packit Service |
4684c1 |
realloc(j->
|
|
Packit Service |
4684c1 |
http_request,
|
|
Packit Service |
4684c1 |
j->
|
|
Packit Service |
4684c1 |
request_length
|
|
Packit Service |
4684c1 |
+ r + 1);
|
|
Packit Service |
4684c1 |
if (j->http_request !=
|
|
Packit Service |
4684c1 |
NULL) {
|
|
Packit Service |
4684c1 |
memcpy(j->
|
|
Packit Service |
4684c1 |
http_request
|
|
Packit Service |
4684c1 |
+
|
|
Packit Service |
4684c1 |
j->
|
|
Packit Service |
4684c1 |
request_length,
|
|
Packit Service |
4684c1 |
buf, r);
|
|
Packit Service |
4684c1 |
j->request_length
|
|
Packit Service |
4684c1 |
+= r;
|
|
Packit Service |
4684c1 |
j->http_request[j->
|
|
Packit Service |
4684c1 |
request_length]
|
|
Packit Service |
4684c1 |
= '\0';
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
j->http_state =
|
|
Packit Service |
4684c1 |
HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
/* check if we have a full HTTP header */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
j->http_response = NULL;
|
|
Packit Service |
4684c1 |
if (j->http_state == HTTP_STATE_REQUEST && j->http_request != NULL) {
|
|
Packit Service |
4684c1 |
if ((http == 0
|
|
Packit Service |
4684c1 |
&& strchr(j->
|
|
Packit Service |
4684c1 |
http_request,
|
|
Packit Service |
4684c1 |
'\n'))
|
|
Packit Service |
4684c1 |
|| strstr(j->
|
|
Packit Service |
4684c1 |
http_request,
|
|
Packit Service |
4684c1 |
"\r\n\r\n")
|
|
Packit Service |
4684c1 |
|| strstr(j->
|
|
Packit Service |
4684c1 |
http_request,
|
|
Packit Service |
4684c1 |
"\n\n")) {
|
|
Packit Service |
4684c1 |
if (get_response(j->
|
|
Packit Service |
4684c1 |
tls_session,
|
|
Packit Service |
4684c1 |
j->
|
|
Packit Service |
4684c1 |
http_request,
|
|
Packit Service |
4684c1 |
&j->
|
|
Packit Service |
4684c1 |
http_response,
|
|
Packit Service |
4684c1 |
&j->
|
|
Packit Service |
4684c1 |
response_length)) {
|
|
Packit Service |
4684c1 |
j->http_state =
|
|
Packit Service |
4684c1 |
HTTP_STATE_RESPONSE;
|
|
Packit Service |
4684c1 |
j->response_written
|
|
Packit Service |
4684c1 |
= 0;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (FD_ISSET(j->fd, &wr)) {
|
|
Packit Service |
4684c1 |
/* write partial response request */
|
|
Packit Service |
4684c1 |
int r;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (j->handshake_ok == 0) {
|
|
Packit Service |
4684c1 |
retry_handshake(j);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (j->handshake_ok == 1 && j->http_response == NULL) {
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
} else if (j->handshake_ok == 1 && j->http_response != NULL) {
|
|
Packit Service |
4684c1 |
r = gnutls_record_send(j->tls_session,
|
|
Packit Service |
4684c1 |
j->http_response
|
|
Packit Service |
4684c1 |
+
|
|
Packit Service |
4684c1 |
j->response_written,
|
|
Packit Service |
4684c1 |
MIN(j->response_length
|
|
Packit Service |
4684c1 |
-
|
|
Packit Service |
4684c1 |
j->response_written,
|
|
Packit Service |
4684c1 |
SMALL_READ_TEST));
|
|
Packit Service |
4684c1 |
if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
|
|
Packit Service |
4684c1 |
/* do nothing */
|
|
Packit Service |
4684c1 |
} else if (r <= 0) {
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
if (r < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error while sending data\n");
|
|
Packit Service |
4684c1 |
GERR(r);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
check_alert(j->tls_session,
|
|
Packit Service |
4684c1 |
r);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
j->response_written += r;
|
|
Packit Service |
4684c1 |
/* check if we have written a complete response */
|
|
Packit Service |
4684c1 |
if (j->response_written ==
|
|
Packit Service |
4684c1 |
j->response_length) {
|
|
Packit Service |
4684c1 |
if (http != 0)
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_CLOSING;
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_REQUEST;
|
|
Packit Service |
4684c1 |
free(j->
|
|
Packit Service |
4684c1 |
http_response);
|
|
Packit Service |
4684c1 |
j->http_response = NULL;
|
|
Packit Service |
4684c1 |
j->response_length = 0;
|
|
Packit Service |
4684c1 |
j->request_length = 0;
|
|
Packit Service |
4684c1 |
j->http_request[0] = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
j->request_length = 0;
|
|
Packit Service |
4684c1 |
j->http_request[0] = 0;
|
|
Packit Service |
4684c1 |
j->http_state = HTTP_STATE_REQUEST;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
lloopend(listener_list, j);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* loop through all connections, closing those that are in error */
|
|
Packit Service |
4684c1 |
lloopstart(listener_list, j) {
|
|
Packit Service |
4684c1 |
if (j->http_state == HTTP_STATE_CLOSING) {
|
|
Packit Service |
4684c1 |
ldeleteinc(listener_list, j);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
lloopend(listener_list, j);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_certificate_free_credentials(cert_cred);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_SRP
|
|
Packit Service |
4684c1 |
if (srp_cred)
|
|
Packit Service |
4684c1 |
gnutls_srp_free_server_credentials(srp_cred);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_PSK
|
|
Packit Service |
4684c1 |
if (psk_cred)
|
|
Packit Service |
4684c1 |
gnutls_psk_free_server_credentials(psk_cred);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef ENABLE_ANON
|
|
Packit Service |
4684c1 |
gnutls_anon_free_server_credentials(dh_cred);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (noticket == 0)
|
|
Packit Service |
4684c1 |
gnutls_free(session_ticket_key.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (earlydata)
|
|
Packit Service |
4684c1 |
gnutls_anti_replay_deinit(anti_replay);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (nodb == 0)
|
|
Packit Service |
4684c1 |
wrap_db_deinit();
|
|
Packit Service |
4684c1 |
gnutls_global_deinit();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void cmd_parser(int argc, char **argv)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
optionProcess(&gnutls_servOptions, argc, argv);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
disable_client_cert = HAVE_OPT(DISABLE_CLIENT_CERT);
|
|
Packit Service |
4684c1 |
require_cert = ENABLED_OPT(REQUIRE_CLIENT_CERT);
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(DEBUG))
|
|
Packit Service |
4684c1 |
debug = OPT_VALUE_DEBUG;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(QUIET))
|
|
Packit Service |
4684c1 |
verbose = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PRIORITY))
|
|
Packit Service |
4684c1 |
priorities = OPT_ARG(PRIORITY);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(LIST)) {
|
|
Packit Service |
4684c1 |
print_list(priorities, verbose);
|
|
Packit Service |
4684c1 |
exit(0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
nodb = HAVE_OPT(NODB);
|
|
Packit Service |
4684c1 |
noticket = HAVE_OPT(NOTICKET);
|
|
Packit Service |
4684c1 |
earlydata = HAVE_OPT(EARLYDATA);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(ECHO))
|
|
Packit Service |
4684c1 |
http = 0;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
http = 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
record_max_size = OPT_VALUE_RECORDSIZE;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509FMTDER))
|
|
Packit Service |
4684c1 |
x509ctype = GNUTLS_X509_FMT_DER;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
x509ctype = GNUTLS_X509_FMT_PEM;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
generate = HAVE_OPT(GENERATE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(DHPARAMS))
|
|
Packit Service |
4684c1 |
dh_params_file = OPT_ARG(DHPARAMS);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(ALPN)) {
|
|
Packit Service |
4684c1 |
alpn_protos = STACKLST_OPT(ALPN);
|
|
Packit Service |
4684c1 |
alpn_protos_size = STACKCT_OPT(ALPN);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509KEYFILE)) {
|
|
Packit Service |
4684c1 |
x509_keyfile = STACKLST_OPT(X509KEYFILE);
|
|
Packit Service |
4684c1 |
x509_keyfile_size = STACKCT_OPT(X509KEYFILE);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509CERTFILE)) {
|
|
Packit Service |
4684c1 |
x509_certfile = STACKLST_OPT(X509CERTFILE);
|
|
Packit Service |
4684c1 |
x509_certfile_size = STACKCT_OPT(X509CERTFILE);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (x509_certfile_size != x509_keyfile_size) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "The certificate number provided (%u) doesn't match the keys (%u)\n",
|
|
Packit Service |
4684c1 |
x509_certfile_size, x509_keyfile_size);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509CAFILE))
|
|
Packit Service |
4684c1 |
x509_cafile = OPT_ARG(X509CAFILE);
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(X509CRLFILE))
|
|
Packit Service |
4684c1 |
x509_crlfile = OPT_ARG(X509CRLFILE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(RAWPKKEYFILE)) {
|
|
Packit Service |
4684c1 |
rawpk_keyfile = STACKLST_OPT(RAWPKKEYFILE);
|
|
Packit Service |
4684c1 |
rawpk_keyfile_size = STACKCT_OPT(RAWPKKEYFILE);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(RAWPKFILE)) {
|
|
Packit Service |
4684c1 |
rawpk_file = STACKLST_OPT(RAWPKFILE);
|
|
Packit Service |
4684c1 |
rawpk_file_size = STACKCT_OPT(RAWPKFILE);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rawpk_file_size != rawpk_keyfile_size) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "The number of raw public-keys provided (%u) doesn't match the number of corresponding private keys (%u)\n",
|
|
Packit Service |
4684c1 |
rawpk_file_size, rawpk_keyfile_size);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SRPPASSWD))
|
|
Packit Service |
4684c1 |
srp_passwd = OPT_ARG(SRPPASSWD);
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SRPPASSWDCONF))
|
|
Packit Service |
4684c1 |
srp_passwd_conf = OPT_ARG(SRPPASSWDCONF);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(PSKPASSWD))
|
|
Packit Service |
4684c1 |
psk_passwd = OPT_ARG(PSKPASSWD);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(OCSP_RESPONSE)) {
|
|
Packit Service |
4684c1 |
ocsp_responses = STACKLST_OPT(OCSP_RESPONSE);
|
|
Packit Service |
4684c1 |
ocsp_responses_size = STACKCT_OPT(OCSP_RESPONSE);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SNI_HOSTNAME))
|
|
Packit Service |
4684c1 |
sni_hostname = OPT_ARG(SNI_HOSTNAME);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(SNI_HOSTNAME_FATAL))
|
|
Packit Service |
4684c1 |
sni_hostname_fatal = 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (HAVE_OPT(HTTPDATA))
|
|
Packit Service |
4684c1 |
http_data_file = OPT_ARG(HTTPDATA);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* session resuming support */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define SESSION_ID_SIZE 128
|
|
Packit Service |
4684c1 |
#define SESSION_DATA_SIZE (16*1024)
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
typedef struct {
|
|
Packit Service |
4684c1 |
unsigned char session_id[SESSION_ID_SIZE];
|
|
Packit Service |
4684c1 |
unsigned int session_id_size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_datum_t session_data;
|
|
Packit Service |
4684c1 |
} CACHE;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static CACHE *cache_db;
|
|
Packit Service |
4684c1 |
static int cache_db_ptr;
|
|
Packit Service |
4684c1 |
static int cache_db_alloc;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void wrap_db_init(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void wrap_db_deinit(void)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < cache_db_ptr; i++)
|
|
Packit Service |
4684c1 |
free(cache_db[i].session_data.data);
|
|
Packit Service |
4684c1 |
free(cache_db);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
wrap_db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
time_t now = time(0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (key.size > SESSION_ID_SIZE)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_DB_ERROR;
|
|
Packit Service |
4684c1 |
if (data.size > SESSION_DATA_SIZE)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_DB_ERROR;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (cache_db_ptr < cache_db_alloc)
|
|
Packit Service |
4684c1 |
i = cache_db_ptr++;
|
|
Packit Service |
4684c1 |
else {
|
|
Packit Service |
4684c1 |
/* find empty or expired slot to store the new entry */
|
|
Packit Service |
4684c1 |
for (i = 0; i < cache_db_ptr; i++)
|
|
Packit Service |
4684c1 |
if (cache_db[i].session_id_size == 0 ||
|
|
Packit Service |
4684c1 |
!(now <
|
|
Packit Service |
4684c1 |
gnutls_db_check_entry_expire_time(&cache_db[i].
|
|
Packit Service |
4684c1 |
session_data)))
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (i == cache_db_ptr) {
|
|
Packit Service |
4684c1 |
/* try to allocate additional slots */
|
|
Packit Service |
4684c1 |
if (cache_db_ptr == ssl_session_cache) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Error: too many sessions\n");
|
|
Packit Service |
4684c1 |
return GNUTLS_E_DB_ERROR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
cache_db_alloc = cache_db_alloc * 2 + 1;
|
|
Packit Service |
4684c1 |
cache_db = realloc(cache_db,
|
|
Packit Service |
4684c1 |
cache_db_alloc * sizeof(CACHE));
|
|
Packit Service |
4684c1 |
if (!cache_db)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
4684c1 |
memset(cache_db + cache_db_ptr, 0,
|
|
Packit Service |
4684c1 |
(cache_db_alloc - cache_db_ptr) * sizeof(CACHE));
|
|
Packit Service |
4684c1 |
cache_db_ptr++;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memcpy(cache_db[i].session_id, key.data, key.size);
|
|
Packit Service |
4684c1 |
cache_db[i].session_id_size = key.size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* resize the data slot if needed */
|
|
Packit Service |
4684c1 |
if (cache_db[i].session_data.size < data.size) {
|
|
Packit Service |
4684c1 |
cache_db[i].session_data.data =
|
|
Packit Service |
4684c1 |
realloc(cache_db[i].session_data.data,
|
|
Packit Service |
4684c1 |
data.size);
|
|
Packit Service |
4684c1 |
if (!cache_db[i].session_data.data)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
memcpy(cache_db[i].session_data.data, data.data, data.size);
|
|
Packit Service |
4684c1 |
cache_db[i].session_data.size = data.size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t res = { NULL, 0 };
|
|
Packit Service |
4684c1 |
time_t now = time(0);
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < cache_db_ptr; i++) {
|
|
Packit Service |
4684c1 |
if (key.size == cache_db[i].session_id_size &&
|
|
Packit Service |
4684c1 |
memcmp(key.data, cache_db[i].session_id,
|
|
Packit Service |
4684c1 |
key.size) == 0 &&
|
|
Packit Service |
4684c1 |
now < gnutls_db_check_entry_expire_time(&cache_db[i].
|
|
Packit Service |
4684c1 |
session_data)) {
|
|
Packit Service |
4684c1 |
res.size = cache_db[i].session_data.size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
res.data = malloc(res.size);
|
|
Packit Service |
4684c1 |
if (res.data == NULL)
|
|
Packit Service |
4684c1 |
return res;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memcpy(res.data, cache_db[i].session_data.data,
|
|
Packit Service |
4684c1 |
res.size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return res;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return res;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int wrap_db_delete(void *dbf, gnutls_datum_t key)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < cache_db_ptr; i++) {
|
|
Packit Service |
4684c1 |
if (key.size == cache_db[i].session_id_size &&
|
|
Packit Service |
4684c1 |
memcmp(key.data, cache_db[i].session_id,
|
|
Packit Service |
4684c1 |
key.size) == 0) {
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cache_db[i].session_id_size = 0;
|
|
Packit Service |
4684c1 |
free(cache_db[i].session_data.data);
|
|
Packit Service |
4684c1 |
cache_db[i].session_data.data = NULL;
|
|
Packit Service |
4684c1 |
cache_db[i].session_data.size = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return GNUTLS_E_DB_ERROR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
anti_replay_db_add(void *dbf, time_t exp, const gnutls_datum_t *key, const gnutls_datum_t *data)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
time_t now = time(0);
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = 0; i < cache_db_ptr; i++) {
|
|
Packit Service |
4684c1 |
if (key->size == cache_db[i].session_id_size &&
|
|
Packit Service |
4684c1 |
memcmp(key->data, cache_db[i].session_id,
|
|
Packit Service |
4684c1 |
key->size) == 0 &&
|
|
Packit Service |
4684c1 |
now < gnutls_db_check_entry_expire_time(&cache_db[i].
|
|
Packit Service |
4684c1 |
session_data))
|
|
Packit Service |
4684c1 |
return GNUTLS_E_DB_ENTRY_EXISTS;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return wrap_db_store(dbf, *key, *data);
|
|
Packit Service |
4684c1 |
}
|