When using rpcapd one may want the forwarded traffic to be encrypted.
When running rpcapd via initd it is relatively easy to add stunnel but
the client still have to implement TLS. Or one could also use an ssh
tunnel but it's a lot of setup. Ultimately, it is simpler than rpcap
protocol could run on SSL natively. So this patch adds a -S option to
rpcapd that will wrap the data socket into a TLS tunnel (in both passive
anbd active mode, as long as it's TCP not UDP).
The start capture message has an additional flag: ssl, asking the client
to initiate a TLS handshake once he is connected to the data socket.
This patch is not polished as I'm more interested in early opinions at
this stage. Please let me know what you think of the idea and its
implementation so far.
Proof of concept:
generate a private key, a self signed root cert:
$ openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 36500 -out cert.pem
then run rpcapd with option -S (ssl) and -K and -C:
$ rpcapd -n -S -K key.pem -C cert.pem
Once recompiled, tcpdump can attach to this rpcap:// service and the
traffic will be encrypted.
rpcapd/win32-svc.h \
sockutils.c \
sockutils.h \
+ sslutils.c \
+ sslutils.h \
scanner.l \
testprogs/CMakeLists.txt \
testprogs/Makefile.in \
$as_echo "#define ENABLE_REMOTE /**/" >>confdefs.h
- SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+ SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
BUILD_RPCAPD=build-rpcapd
INSTALL_RPCAPD=install-rpcapd
;;
AC_DEFINE(ENABLE_REMOTE,,
[Define to 1 if remote packet capture is to be supported])
- SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c"
+ SSRC="$SSRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c"
BUILD_RPCAPD=build-rpcapd
INSTALL_RPCAPD=install-rpcapd
;;
#include "rpcap-protocol.h"
#include "pcap-rpcap.h"
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
/*
* This file contains the pcap module for capturing from a remote machine's
* interfaces using the RPCAP protocol.
SOCKET rmt_sockctrl; /* socket ID of the socket used for the control connection */
SOCKET rmt_sockdata; /* socket ID of the socket used for the data connection */
+#ifdef HAVE_OPENSSL
+ SSL *ssl; /* To transport rmt_sockdata via TLS */
+#endif
int rmt_flags; /* we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture() */
int rmt_capstarted; /* 'true' if the capture is already started (needed to knoe if we have to call the pcap_startcapture() */
char *currentfilter; /* Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on. */
static int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf);
static void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf);
static int rpcap_discard(SOCKET sock, uint32 len, char *errbuf);
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size);
+static int rpcap_read_packet_msg(struct pcap_rpcap const *, pcap_t *p, size_t size);
/****************************************************
* *
tv.tv_sec = p->opt.timeout / 1000;
tv.tv_usec = (suseconds_t)((p->opt.timeout - tv.tv_sec * 1000) * 1000);
- /* Watch out sockdata to see if it has input */
- FD_ZERO(&rfds);
+#ifdef HAVE_OPENSSL
+ /* Check if we still have bytes available in the last decoded TLS record.
+ * If that's the case, we know SSL_read will not block. */
+ retval = pr->ssl && SSL_pending(pr->ssl) > 0;
+#endif
+ if (! retval)
+ {
+ /* Watch out sockdata to see if it has input */
+ FD_ZERO(&rfds);
- /*
- * 'fp->rmt_sockdata' has always to be set before calling the select(),
- * since it is cleared by the select()
- */
- FD_SET(pr->rmt_sockdata, &rfds);
+ /*
+ * 'fp->rmt_sockdata' has always to be set before calling the select(),
+ * since it is cleared by the select()
+ */
+ FD_SET(pr->rmt_sockdata, &rfds);
- retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1)
- {
-#ifndef _WIN32
- if (errno == EINTR)
+ retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
+
+ if (retval == -1)
{
- /* Interrupted. */
- return 0;
- }
+#ifndef _WIN32
+ if (errno == EINTR)
+ {
+ /* Interrupted. */
+ return 0;
+ }
#endif
- sock_geterror("select(): ", p->errbuf, PCAP_ERRBUF_SIZE);
- return -1;
+ sock_geterror("select(): ", p->errbuf, PCAP_ERRBUF_SIZE);
+ return -1;
+ }
}
/* There is no data waiting, so return '0' */
* The size we should get is the size of the
* packet header.
*/
- status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
- sizeof(struct rpcap_header));
+ status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header));
if (status == -1)
{
/* Network error. */
"Server sent us a message larger than the largest expected packet message");
return -1;
}
- status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
- sizeof(struct rpcap_header) + plen);
+ status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header) + plen);
if (status == -1)
{
/* Network error. */
int sockbufsize = 0;
uint32 server_sockbufsize;
+#ifdef HAVE_OPENSSL
+ // Take the opportunity to clear pr->ssl before any goto error,
+ // as it seems pr->priv is not zeroed after its malloced.
+ pr->ssl = NULL;
+#endif
+
/*
* Let's check if sampling has been required.
* If so, let's set it first
/* Let's save the socket of the data connection */
pr->rmt_sockdata = sockdata;
+#ifdef HAVE_OPENSSL
+ if (startcapreply.ssl) {
+ pr->ssl = ssl_promotion(0, sockdata, fp->errbuf, PCAP_ERRBUF_SIZE);
+ if (! pr->ssl) goto error;
+ }
+#endif
+
/*
* Set the size of the socket buffer for the data socket.
* It has the same size as the local capture buffer used
(void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
error_nodiscard:
+#ifdef HAVE_OPENSSL
+ if (pr->ssl) {
+ SSL_free(pr->ssl); // Have to be done before the socket is closed
+ pr->ssl = NULL;
+ }
+#endif
+
if ((sockdata) && (sockdata != -1)) /* we can be here because sockdata said 'error' */
sock_close(sockdata, NULL, 0);
* Read bytes into the pcap_t's buffer until we have the specified
* number of bytes read or we get an error or interrupt indication.
*/
-static int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size)
+static int rpcap_read_packet_msg(struct pcap_rpcap const *rp, pcap_t *p, size_t size)
{
u_char *bp;
int cc;
* We haven't read all of the packet header yet.
* Read what remains, which could be all of it.
*/
- bytes_read = sock_recv(sock, bp, size - cc,
- SOCK_RECEIVEALL_NO|SOCK_EOF_IS_ERROR, p->errbuf,
- PCAP_ERRBUF_SIZE);
+#ifdef HAVE_OPENSSL
+ if (rp->ssl)
+ {
+ bytes_read = ssl_recv(rp->ssl, bp, size - cc, p->errbuf, PCAP_ERRBUF_SIZE);
+ }
+ else
+#endif
+ {
+ bytes_read = sock_recv(rp->rmt_sockdata, bp, size - cc,
+ SOCK_RECEIVEALL_NO|SOCK_EOF_IS_ERROR, p->errbuf,
+ PCAP_ERRBUF_SIZE);
+ }
+
if (bytes_read == -1)
{
/*
int32 bufsize; /* Size of the user buffer allocated by WinPcap; it can be different from the one we chose */
uint16 portdata; /* Network port on which the server is waiting at (passive mode only) */
uint16 dummy; /* Must be zero */
+ uint8 ssl:1; /* Only known flag so far: client must connect with TLS */
};
/*
log-stderr.c \
rpcapd.c
-OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o
+OBJ = $(SRC:.c=.o) ../rpcap-protocol.o ../sockutils.o ../fmtutils.o ../sslutils.o
PUBHDR =
HDR = $(PUBHDR) log.h
#include "daemon.h"
#include "log.h"
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include "sslutils.h"
+#endif
+
#define RPCAP_TIMEOUT_INIT 90 /* Initial timeout for RPCAP connections (default: 90 sec) */
#define RPCAP_TIMEOUT_RUNTIME 180 /* Run-time timeout for RPCAP connections (default: 3 min) */
#define RPCAP_SUSPEND_WRONGAUTH 1 /* If the authentication is wrong, stops 1 sec before accepting a new auth message */
struct session {
SOCKET sockctrl_out;
SOCKET sockdata;
+#ifdef HAVE_OPENSSL
+ SSL *ssl; // optional SSL handler for the data transported in sockdata
+#endif
uint8 protocol_version;
pcap_t *fp;
unsigned int TotCapt;
static int rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp);
static int rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
static int rpcapd_discard(SOCKET sock, uint32 len);
+static void session_close(struct session *);
+static int session_send_data(struct session const *, const char *, size_t, char *, size_t);
int
daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nullAuthAllowed)
#endif
threaddata.have_thread = 0;
}
- if (session->sockdata)
- {
- sock_close(session->sockdata, NULL, 0);
- session->sockdata = 0;
- }
- pcap_close(session->fp);
+
+ session_close(session);
free(session);
session = NULL;
}
goto error;
}
+#ifdef HAVE_OPENSSL
+ session->ssl = NULL;
+#endif
+
// Open the selected device
if ((session->fp = pcap_open_live(source,
ntohl(startcapreq.snaplen),
startcapreply->portdata = htons(port);
}
+#ifdef HAVE_OPENSSL
+ startcapreply->ssl = !!uses_ssl;
+#endif
+
if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a message and give up.
sockdata = socktemp;
}
+#ifdef HAVE_OPENSSL
+ if (uses_ssl)
+ {
+ /* In both active or passive cases, wait for the client to initiate the
+ * TLS handshake. Yes during that time the control socket will not be
+ * served, but the same was true from the above call to accept(). */
+ SSL *ssl = ssl_promotion(1, sockdata, errbuf, PCAP_ERRBUF_SIZE);
+ if (! ssl)
+ {
+ rpcapd_log(LOGPRIO_ERROR, "TLS handshake failed: %s", errbuf);
+ goto error;
+ }
+ session->ssl = ssl;
+ }
+#endif
+
session->sockdata = sockdata;
// Now we have to create a new thread to receive packets
{
if (session->fp)
pcap_close(session->fp);
+#ifdef HAVE_OPENSSL
+ if (session->ssl)
+ SSL_free(session->ssl);
+#endif
free(session);
}
{
if (session->fp)
pcap_close(session->fp);
+#ifdef HAVE_OPENSSL
+ if (session->ssl)
+ SSL_free(session->ssl);
+#endif
free(session);
}
#endif
threaddata->have_thread = 0;
}
- if (session->sockdata)
- {
- sock_close(session->sockdata, NULL, 0);
- session->sockdata = 0;
- }
- pcap_close(session->fp);
+ session_close(session);
rpcap_createhdr(&header, pars->protocol_version,
RPCAP_MSG_ENDCAP_REPLY, 0, 0);
// Send the packet
// If the client dropped the connection, don't report an
// error, just quit.
- status = sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
+ status = session_send_data(session, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE);
if (status < 0)
{
if (status == -1)
}
error:
- closesocket(session->sockdata);
- session->sockdata = 0;
+ session_close(session);
free(sendbuf);
}
return 0;
}
+
+/*
+ * Close the socket associated with the session, the optional SSL handle,
+ * and the underlying packet capture handle.
+ */
+static void session_close(struct session *session)
+{
+#ifdef HAVE_OPENSSL
+ if (session->ssl)
+ {
+ SSL_free(session->ssl); // Must happen *before* the socket is closed
+ session->ssl = NULL;
+ }
+#endif
+
+ if (session->sockdata)
+ {
+ sock_close(session->sockdata, NULL, 0);
+ session->sockdata = 0;
+ }
+
+ pcap_close(session->fp);
+}
+
+static int session_send_data(struct session const *session, const char *buffer, size_t size, char *errbuf, size_t errbuflen)
+{
+#ifdef HAVE_OPENSSL
+ if (session->ssl)
+ {
+ return ssl_send(session->ssl, buffer, size, errbuf, errbuflen);
+ }
+ else
+#endif
+ {
+ return sock_send(session->sockdata, buffer, size, errbuf, errbuflen);
+ }
+}
#include "daemon.h" // the true main() method of this daemon
#include "log.h"
+#ifdef HAVE_OPENSSL
+#include "sslutils.h"
+#endif
+
#ifdef _WIN32
#include <process.h> // for thread stuff
#include "win32-svc.h" // for Win32 service stuff
mainhints.ai_socktype = SOCK_STREAM;
// Getting the proper command line options
- while ((retval = getopt(argc, argv, "b:dhip:4l:na:s:f:v")) != -1)
+# ifdef HAVE_OPENSSL
+# define SSL_CLOPTS "SK:C:"
+# else
+# define SSL_CLOPTS ""
+# endif
+
+# define CLOPTS "b:dhip:4l:na:s:f:v" SSL_CLOPTS
+
+ while ((retval = getopt(argc, argv, CLOPTS)) != -1)
{
switch (retval)
{
case 's':
strlcpy(savefile, optarg, MAX_LINE);
break;
+#ifdef HAVE_OPENSSL
+ case 'S':
+ uses_ssl = 1;
+ break;
+ case 'K':
+ snprintf(ssl_keyfile, sizeof ssl_keyfile, "%s", optarg);
+ break;
+ case 'C':
+ snprintf(ssl_certfile, sizeof ssl_certfile, "%s", optarg);
+ break;
+#endif
case 'h':
printusage();
exit(0);
#endif
#ifndef _WIN32
+# ifdef HAVE_OPENSSL
+ if (uses_ssl) init_ssl_or_die(1);
+# endif
if (isrunbyinetd)
{
//
--- /dev/null
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_OPENSSL
+#include <stdlib.h>
+
+#include "portability.h"
+#include "sslutils.h"
+#include "pcap/pcap.h"
+
+int uses_ssl; //!< '1' to use TLS over the data socket
+char ssl_keyfile[PATH_MAX]; //!< file containing the private key in PEM format
+char ssl_certfile[PATH_MAX]; //!< file containing the server's certificate in PEM format
+char ssl_rootfile[PATH_MAX]; //!< file containing the list of CAs trusted by the client
+// TODO: a way to set ssl_rootfile from the command line, or an envvar?
+
+// TODO: lock?
+static SSL_CTX *ctx;
+
+static int ssl_init_once(int is_server, char *errbuf, size_t errbuflen)
+{
+ static int inited = 0;
+ if (inited) return 0;
+
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_ssl_algorithms();
+
+ SSL_METHOD const *meth = SSLv23_method();
+ ctx = SSL_CTX_new(meth);
+ if (! ctx)
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+
+ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+
+ if (is_server)
+ {
+ char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem";
+ if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+
+ char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem";
+ if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL));
+ goto die;
+ }
+ }
+ else
+ {
+ if (ssl_rootfile[0])
+ {
+ if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile);
+ goto die;
+ }
+ }
+ else
+ {
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ }
+ }
+
+#if 0
+ if (! RAND_load_file(RANDOM, 1024*1024))
+ {
+ pcap_snprintf(errbuf, errbuflen, "Cannot init random");
+ goto die;
+ }
+
+ if (is_server)
+ {
+ SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context));
+ }
+#endif
+
+ inited = 1;
+ return 0;
+
+die:
+ return -1;
+}
+
+void init_ssl_or_die(int is_server)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ if (ssl_init_once(is_server, errbuf, sizeof errbuf) < 0)
+ {
+ fprintf(stderr, "%s\n", errbuf);
+ exit(3);
+ }
+}
+
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen)
+{
+ if (ssl_init_once(is_server, errbuf, errbuflen) < 0)
+ {
+ return NULL;
+ }
+
+ SSL *ssl = SSL_new(ctx);
+ SSL_set_fd(ssl, s);
+
+ if (is_server)
+ {
+ if (SSL_accept(ssl) <= 0)
+ {
+ pcap_snprintf(errbuf, errbuflen, "SSL_accept(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+ }
+ else
+ {
+ if (SSL_connect(ssl) <= 0)
+ {
+ pcap_snprintf(errbuf, errbuflen, "SSL_connect(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+ }
+
+ return ssl;
+}
+
+// Same return value as sock_send:
+// 0 on OK, -1 on error but closed connection (-2).
+int ssl_send(SSL *ssl, char const *buffer, size_t size, char *errbuf, size_t errbuflen)
+{
+ int status = SSL_write(ssl, buffer, size);
+ if (status > 0)
+ {
+ // "SSL_write() will only return with success, when the complete contents (...) has been written."
+ return 0;
+ }
+ else
+ {
+ int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error?
+ if (ssl_err == SSL_ERROR_ZERO_RETURN)
+ {
+ return -2;
+ }
+ else if (ssl_err == SSL_ERROR_SYSCALL)
+ {
+#ifndef _WIN32
+ if (errno == ECONNRESET || errno == EPIPE) return -2;
+#endif
+ }
+ pcap_snprintf(errbuf, errbuflen, "SSL_write(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+}
+
+// Same return status as sock_recv(SOCK_EOF_IS_ERROR):
+// -3 for EINTR, -1 on error and EOF, or number of bytes read
+int ssl_recv(SSL *ssl, unsigned char *buffer, size_t size, char *errbuf, size_t errbuflen)
+{
+ int status = SSL_read(ssl, buffer, size);
+ if (status <= 0)
+ {
+ int ssl_err = SSL_get_error(ssl, status);
+ if (ssl_err == SSL_ERROR_ZERO_RETURN)
+ {
+ pcap_snprintf(errbuf, errbuflen, "The other host terminated the connection.");
+ return -1;
+ }
+ else if (ssl_err == SSL_ERROR_SYSCALL)
+ {
+#ifndef _WIN32
+ if (errno == EINTR)
+ {
+ return -3;
+ }
+ else
+ {
+ pcap_snprintf(errbuf, errbuflen, "SSL_read(): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+#endif
+ }
+ }
+ return status;
+}
+
+#endif // HAVE_OPENSSL
--- /dev/null
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __SSLUTILS_H__
+#define __SSLUTILS_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include "sockutils.h"
+
+/*
+ * Configuration parameters
+ */
+
+extern int uses_ssl;
+extern char ssl_keyfile[PATH_MAX];
+extern char ssl_certfile[PATH_MAX];
+extern char ssl_rootfile[PATH_MAX];
+
+/*
+ * Utility functions
+ */
+
+void init_ssl_or_die(int is_server);
+SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen);
+int ssl_send(SSL *, char const *buffer, size_t size, char *errbuf, size_t errbuflen);
+int ssl_recv(SSL *, unsigned char *buffer, size_t size, char *errbuf, size_t errbuflen);
+
+#endif // HAVE_OPENSSL
+
+#endif // __SSLUTILS_H__