aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml4
-rw-r--r--CMakeLists.txt29
-rw-r--r--nDPIsrvd.c211
-rwxr-xr-xscripts/generate-tls-ca.sh32
-rwxr-xr-xscripts/generate-tls-cert.sh17
-rw-r--r--tls-cli.c167
-rw-r--r--tls-srv.c146
7 files changed, 599 insertions, 7 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c273052f0..35d5e626d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -51,6 +51,7 @@ jobs:
sudo apt-get update
sudo apt-get install autoconf automake cmake libtool pkg-config gettext libjson-c-dev flex bison libpcap-dev zlib1g-dev
sudo apt-get install ${{ matrix.compiler }} lcov iproute2
+ sudo apt-get install rpm alien
- name: Install Ubuntu Prerequisites (libgcrypt)
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.ndpid_gcrypt, '-DNDPI_WITH_GCRYPT=ON')
run: |
@@ -93,6 +94,9 @@ jobs:
- name: CPack DEB
run: |
cd ./build && cpack -G DEB && sudo dpkg -i nDPId-*.deb && cd ..
+ - name: CPack RPM
+ run: |
+ cd ./build && cpack -G RPM
- name: systemd test
if: startsWith(matrix.os, 'ubuntu-latest') && startsWith(matrix.compiler, 'default-cc')
run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ecb1dece3..a770388e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,13 +10,20 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
find_package(PkgConfig REQUIRED)
+set(CMAKE_PROJECT_HOMEPAGE_URL "https://github.com/utoni/nDPId")
+set(CPACK_PACKAGE_NAME "nDPId")
set(CPACK_PACKAGE_CONTACT "toni@impl.cc")
-set(CPACK_DEBIAN_PACKAGE_NAME "nDPId")
-set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Tiny nDPI based deep packet inspection daemons / toolkit.")
+set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
set(CPACK_PACKAGE_VERSION_MAJOR 1)
set(CPACK_PACKAGE_VERSION_MINOR 5)
set(CPACK_PACKAGE_VERSION_PATCH 0)
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_RPM_PACKAGE_LICENSE "GPL-3.0")
+
include(CPack)
include(CheckFunctionExists)
@@ -46,6 +53,7 @@ option(ENABLE_SANITIZER_THREAD "Enable TSAN (does not work together with ASAN)."
option(ENABLE_MEMORY_PROFILING "Enable dynamic memory tracking." OFF)
option(ENABLE_ZLIB "Enable zlib support for nDPId (experimental)." OFF)
option(ENABLE_SYSTEMD "Install systemd components." OFF)
+option(ENABLE_GNUTLS "Enable GnuTLS support for nDPIsrvd TCP connections." ON)
option(BUILD_EXAMPLES "Build C examples." ON)
option(BUILD_NDPI "Clone and build nDPI from github." OFF)
if(BUILD_NDPI)
@@ -134,9 +142,13 @@ if(ENABLE_SANITIZER_THREAD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize=alignment -fsanitize=enum -fsanitize=thread")
endif()
if(ENABLE_ZLIB)
- set(ZLIB_DEFS "-DENABLE_ZLIB=1")
+ set(NDPID_DEFS ${NDPID_DEFS} -DENABLE_ZLIB=1)
pkg_check_modules(ZLIB REQUIRED zlib)
endif()
+if(ENABLE_GNUTLS)
+ set(NDPID_DEFS ${NDPID_DEFS} -DENABLE_GNUTLS=1)
+ pkg_check_modules(GNUTLS REQUIRED gnutls)
+endif()
if(NDPI_WITH_GCRYPT)
message(STATUS "nDPI: Enable GCRYPT")
set(NDPI_ADDITIONAL_ARGS "${NDPI_ADDITIONAL_ARGS} --with-local-libgcrypt")
@@ -276,15 +288,17 @@ target_link_libraries(nDPId "${STATIC_LIBNDPI_LIB}" "${pkgcfg_lib_NDPI_ndpi}"
target_compile_definitions(nDPIsrvd PRIVATE -D_GNU_SOURCE=1 -DGIT_VERSION=\"${GIT_VERSION}\" ${NDPID_DEFS})
target_include_directories(nDPIsrvd PRIVATE ${NDPID_DEPS_INC})
+target_link_libraries(nDPIsrvd "${pkgcfg_lib_GNUTLS_gnutls}")
target_include_directories(nDPId-test PRIVATE ${NDPID_DEPS_INC})
target_compile_options(nDPId-test PRIVATE "-Wno-unused-function" "-pthread")
target_compile_definitions(nDPId-test PRIVATE -D_GNU_SOURCE=1 -DNO_MAIN=1 -DGIT_VERSION=\"${GIT_VERSION}\"
- ${NDPID_DEFS} ${ZLIB_DEFS} ${NDPID_TEST_MPROF_DEFS})
+ ${NDPID_DEFS} ${NDPID_TEST_MPROF_DEFS})
target_include_directories(nDPId-test PRIVATE
"${STATIC_LIBNDPI_INC}" "${DEFAULT_NDPI_INCLUDE}" ${NDPID_DEPS_INC})
target_link_libraries(nDPId-test "${STATIC_LIBNDPI_LIB}" "${pkgcfg_lib_NDPI_ndpi}"
"${pkgcfg_lib_PCRE_pcre}" "${pkgcfg_lib_MAXMINDDB_maxminddb}" "${pkgcfg_lib_ZLIB_z}"
+ "${pkgcfg_lib_GNUTLS_gnutls}"
"${GCRYPT_LIBRARY}" "${GCRYPT_ERROR_LIBRARY}" "${PCAP_LIBRARY}" "${LIBM_LIB}"
"-pthread")
@@ -364,14 +378,19 @@ install(FILES schema/error_event_schema.json schema/daemon_event_schema.json
message(STATUS "--------------------------")
message(STATUS "nDPId GIT_VERSION........: ${GIT_VERSION}")
message(STATUS "Cross Compilation........: ${CMAKE_CROSSCOMPILING}")
+message(STATUS "CMAKE_SYSTEM_NAME........: ${CMAKE_SYSTEM_NAME}")
+message(STATUS "CMAKE_SYSTEM_PROCESSOR...: ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_BUILD_TYPE.........: ${CMAKE_BUILD_TYPE}")
message(STATUS "CMAKE_C_FLAGS............: ${CMAKE_C_FLAGS}")
-message(STATUS "NDPID_DEFS...............: ${NDPID_DEFS}")
+string(REPLACE ";" " " PRETTY_NDPID_DEFS "${NDPID_DEFS}")
+message(STATUS "NDPID_DEFS...............: ${PRETTY_NDPID_DEFS}")
message(STATUS "ENABLE_COVERAGE..........: ${ENABLE_COVERAGE}")
message(STATUS "ENABLE_SANITIZER.........: ${ENABLE_SANITIZER}")
message(STATUS "ENABLE_SANITIZER_THREAD..: ${ENABLE_SANITIZER_THREAD}")
message(STATUS "ENABLE_MEMORY_PROFILING..: ${ENABLE_MEMORY_PROFILING}")
message(STATUS "ENABLE_ZLIB..............: ${ENABLE_ZLIB}")
+message(STATUS "ENABLE_SYSTEMD...........: ${ENABLE_SYSTEMD}")
+message(STATUS "ENABLE_GNUTLS............: ${ENABLE_GNUTLS}")
if(STATIC_LIBNDPI_INSTALLDIR)
message(STATUS "STATIC_LIBNDPI_INSTALLDIR: ${STATIC_LIBNDPI_INSTALLDIR}")
endif()
diff --git a/nDPIsrvd.c b/nDPIsrvd.c
index c2478f452..749d3ad6e 100644
--- a/nDPIsrvd.c
+++ b/nDPIsrvd.c
@@ -1,6 +1,9 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
+#ifdef ENABLE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
#include <netdb.h>
#include <netinet/tcp.h>
#include <pwd.h>
@@ -81,6 +84,10 @@ static int distributor_in_sockfd = -1;
static struct nDPIsrvd_address distributor_in_address = {
.raw.sa_family = 0xFFFF,
};
+#ifdef ENABLE_GNUTLS
+static gnutls_certificate_credentials_t x509_creds = NULL;
+static gnutls_priority_t prio_cache = NULL;
+#endif
static struct
{
@@ -93,6 +100,15 @@ static struct
nDPIsrvd_ull max_remote_descriptors;
nDPIsrvd_ull max_write_buffers;
int bufferbloat_fallback_to_blocking;
+#ifdef ENABLE_GNUTLS
+ int enable_tls;
+ char * tls_proxy_listen_address;
+ char * tls_proxy_connect_address;
+ char * x509_certfile;
+ char * x509_keyfile;
+ char * x509_crlfile;
+ char * x509_cafile;
+#endif
} nDPIsrvd_options = {.pidfile = CMDARG(nDPIsrvd_PIDFILE),
.collector_un_sockpath = CMDARG(COLLECTOR_UNIX_SOCKET),
.distributor_un_sockpath = CMDARG(DISTRIBUTOR_UNIX_SOCKET),
@@ -100,7 +116,6 @@ static struct
.user = CMDARG(DEFAULT_CHUSER),
.group = CMDARG(NULL),
.max_remote_descriptors = nDPIsrvd_MAX_REMOTE_DESCRIPTORS,
- .max_write_buffers = nDPIsrvd_MAX_WRITE_BUFFERS,
.bufferbloat_fallback_to_blocking = 1};
static void logger_nDPIsrvd(struct remote_desc const * const remote,
@@ -169,6 +184,76 @@ void nDPIsrvd_memprof_log(char const * const format, ...)
#endif
#endif
+#ifdef ENABLE_GNUTLS
+static int gtls_global_init(char const * const certfile,
+ char const * const keyfile,
+ char const * const crlfile,
+ char const * const cafile,
+ gnutls_certificate_credentials_t * const x509_creds,
+ gnutls_priority_t * prio_cache)
+{
+ int error;
+
+ if (gnutls_check_version("3.4.6") == NULL)
+ {
+ logger_early(1, "GnuTLS 3.4.6 or later is required.");
+ return -1;
+ }
+ if ((error = gnutls_global_init()) < 0)
+ {
+ logger_early(1, "GnuTLS global init failed %s %s.", gnutls_strerror(error), gnutls_strerror_name(error));
+ return -1;
+ }
+ if ((error = gnutls_certificate_allocate_credentials(x509_creds)) < 0)
+ {
+ logger_early(1,
+ "GnuTLS certificate allocation failed %s %s.",
+ gnutls_strerror(error),
+ gnutls_strerror_name(error));
+ return -1;
+ }
+ if ((error = gnutls_certificate_set_x509_crl_file(*x509_creds, crlfile, GNUTLS_X509_FMT_PEM)) < 0)
+ {
+ logger_early(1,
+ "GnuTLS x509 crl file invalid. PEM format required %s %s.",
+ gnutls_strerror(error),
+ gnutls_strerror_name(error));
+ return -1;
+ }
+ if ((error = gnutls_certificate_set_x509_key_file(*x509_creds, certfile, keyfile, GNUTLS_X509_FMT_PEM)) < 0)
+ {
+ logger_early(1,
+ "GnuTLS x509 cert/key file invalid. PEM format required %s %s.",
+ gnutls_strerror(error),
+ gnutls_strerror_name(error));
+ return -1;
+ }
+ if ((error = gnutls_certificate_set_x509_trust_file(*x509_creds, cafile, GNUTLS_X509_FMT_PEM)) < 0)
+ {
+ logger_early(1,
+ "GnuTLS x509 ca file invalid. PEM format required: %s %s.",
+ gnutls_strerror(error),
+ gnutls_strerror_name(error));
+ return -1;
+ }
+ if ((error = gnutls_priority_init(prio_cache, "SECURE256", NULL)) < 0)
+ {
+ logger_early(1,
+ "GnuTLS priority cache init failed: %s %s.",
+ gnutls_strerror(error),
+ gnutls_strerror_name(error));
+ return -1;
+ }
+#if GNUTLS_VERSION_NUMBER >= 0x030506
+ gnutls_certificate_set_known_dh_params(*x509_creds, GNUTLS_SEC_PARAM_HIGH);
+#else
+ gnutls_certificate_set_dh_params(*x509_creds, GNUTLS_SEC_PARAM_HIGH);
+#endif
+
+ return 0;
+}
+#endif
+
static struct nDPIsrvd_json_buffer * get_read_buffer(struct remote_desc * const remote)
{
switch (remote->sock_type)
@@ -791,7 +876,7 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
{
int opt;
- while ((opt = getopt(argc, argv, "lL:c:dp:s:S:m:u:g:C:Dvh")) != -1)
+ while ((opt = getopt(argc, argv, "lL:c:dp:s:S:m:u:g:C:DvX:x:h")) != -1)
{
switch (opt)
{
@@ -845,6 +930,88 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
case 'v':
fprintf(stderr, "%s", get_nDPId_version());
return 1;
+ case 'X':
+ {
+#ifdef ENABLE_GNUTLS
+ static char * const x509_subopt_token[] = {"listen", "connect", NULL};
+ int errfnd = 0;
+ char * subopts = optarg;
+ char * value;
+
+ while (*subopts != '\0' && !errfnd)
+ {
+ int subopt = getsubopt(&subopts, x509_subopt_token, &value);
+ if (subopt == -1)
+ {
+ logger_early(1, "Invalid subopt: %s", value);
+ return 1;
+ }
+
+ switch (subopt)
+ {
+ case 0: /* listen */
+ nDPIsrvd_options.tls_proxy_listen_address = strdup(value);
+ break;
+ case 1: /* connect */
+ nDPIsrvd_options.tls_proxy_connect_address = strdup(value);
+ break;
+ default:
+ logger_early(1, "Invalid subopt: %s", value);
+ return 1;
+ }
+ }
+
+ nDPIsrvd_options.enable_tls = 1;
+#else
+ logger_early(1, "To use TLS capabilities (`-X'), GnuTLS support required.");
+ return 1;
+#endif
+ break;
+ }
+ case 'x':
+ {
+#ifdef ENABLE_GNUTLS
+ static char * const x509_subopt_token[] = {"cert", "key", "crl", "ca", NULL};
+ int errfnd = 0;
+ char * subopts = optarg;
+ char * value;
+
+ while (*subopts != '\0' && !errfnd)
+ {
+ int subopt = getsubopt(&subopts, x509_subopt_token, &value);
+ if (subopt == -1)
+ {
+ logger_early(1, "Invalid subopt: %s", value);
+ return 1;
+ }
+
+ switch (subopt)
+ {
+ case 0: /* cert */
+ nDPIsrvd_options.x509_certfile = strdup(value);
+ break;
+ case 1: /* key */
+ nDPIsrvd_options.x509_keyfile = strdup(value);
+ break;
+ case 2: /* crl */
+ nDPIsrvd_options.x509_crlfile = strdup(value);
+ break;
+ case 3: /* ca */
+ nDPIsrvd_options.x509_cafile = strdup(value);
+ break;
+ default:
+ logger_early(1, "Invalid subopt: %s", value);
+ return 1;
+ }
+ }
+
+ nDPIsrvd_options.enable_tls = 1;
+#else
+ logger_early(1, "To use TLS capabilities (`-x'), GnuTLS support required.");
+ return 1;
+#endif
+ break;
+ }
case 'h':
default:
fprintf(stderr, "%s\n", get_nDPId_version());
@@ -870,6 +1037,10 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
"\t-s\tPath to a listening UNIX socket (nDPIsrvd Distributor).\n"
"\t \tDefault: %s\n"
"\t-S\tAddress:Port of the listening TCP/IP socket (nDPIsrvd Distributor).\n"
+#ifdef ENABLE_GNUTLS
+ "\t[-X listen=TLS-proxy-listen-address] [-X connect=TLS-proxy-connect-address]\n"
+ "\t[-x cert=PEM-file] [-x key=PEM-file] [-x crl=file] [-x ca=PEM-file]\n"
+#endif
"\t-v\tversion\n"
"\t-h\tthis\n\n",
argv[0],
@@ -917,6 +1088,30 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
}
}
+#ifdef ENABLE_GNUTLS
+ if (nDPIsrvd_options.enable_tls != 0)
+ {
+ if (nDPIsrvd_options.x509_certfile == NULL || nDPIsrvd_options.x509_keyfile == NULL ||
+ nDPIsrvd_options.x509_cafile == NULL)
+ {
+ logger_early(1,
+ "%s: To use nDPIsrvd TLS proxy capabilities, `-x cert', `-x key' and `-x ca' need to be set.",
+ argv[0]);
+ return 1;
+ }
+
+ if ((nDPIsrvd_options.tls_proxy_listen_address == NULL && nDPIsrvd_options.tls_proxy_connect_address == NULL) ||
+ (nDPIsrvd_options.tls_proxy_listen_address != NULL && nDPIsrvd_options.tls_proxy_connect_address != NULL))
+ {
+ logger_early(1,
+ "%s: To use nDPIsrvd TLS proxy capabilities, either `-X listen' or `-X connect' need to be "
+ "set.",
+ argv[0]);
+ return 1;
+ }
+ }
+#endif
+
if (optind < argc)
{
logger_early(1, "%s: Unexpected argument after options", argv[0]);
@@ -1638,6 +1833,18 @@ int main(int argc, char ** argv)
goto error_unlink_sockets;
}
+#ifdef ENABLE_GNUTLS
+ if (nDPIsrvd_options.enable_tls != 0 && gtls_global_init(nDPIsrvd_options.x509_certfile,
+ nDPIsrvd_options.x509_keyfile,
+ nDPIsrvd_options.x509_crlfile,
+ nDPIsrvd_options.x509_cafile,
+ &x509_creds,
+ &prio_cache) != 0)
+ {
+ goto error_unlink_sockets;
+ }
+#endif
+
signal(SIGPIPE, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
diff --git a/scripts/generate-tls-ca.sh b/scripts/generate-tls-ca.sh
new file mode 100755
index 000000000..9fe82b677
--- /dev/null
+++ b/scripts/generate-tls-ca.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env sh
+
+set -e
+
+OUTDIR="$(dirname ${0})"
+
+printf 'Output directory: %s\n' "${OUTDIR}"
+
+printf 'ca\ncert_signing_key' > template
+certtool --generate-privkey > "${OUTDIR}/ca-key.pem"
+certtool --generate-self-signed \
+ --template template \
+ --load-privkey "${OUTDIR}/ca-key.pem" \
+ --outfile "${OUTDIR}/ca-cert.pem"
+rm template
+
+printf 'expiration_days = 365' > template
+certtool --generate-crl --load-ca-privkey "${OUTDIR}/ca-key.pem" \
+ --template template \
+ --load-ca-certificate "${OUTDIR}/ca-cert.pem" \
+ --outfile "${OUTDIR}/crl.pem"
+rm template
+
+printf 'encryption_key\nsigning_key' > template
+certtool --generate-privkey > "${OUTDIR}/server-key.pem"
+certtool --generate-certificate \
+ --template template \
+ --load-privkey "${OUTDIR}/server-key.pem" \
+ --load-ca-certificate "${OUTDIR}/ca-cert.pem" \
+ --load-ca-privkey "${OUTDIR}/ca-key.pem" \
+ --outfile "${OUTDIR}/server-cert.pem"
+rm template
diff --git a/scripts/generate-tls-cert.sh b/scripts/generate-tls-cert.sh
new file mode 100755
index 000000000..0dccbd054
--- /dev/null
+++ b/scripts/generate-tls-cert.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env sh
+
+set -e
+
+OUTDIR="$(dirname ${0})"
+
+printf 'Output directory: %s\n' "${OUTDIR}"
+
+printf 'encryption_key\nsigning_key' > template
+certtool --generate-privkey > "${OUTDIR}/client-key.pem"
+certtool --generate-certificate \
+ --template template \
+ --load-privkey "${OUTDIR}/client-key.pem" \
+ --load-ca-certificate "${OUTDIR}/ca-cert.pem" \
+ --load-ca-privkey "${OUTDIR}/ca-key.pem" \
+ --outfile "${OUTDIR}/client-cert.pem"
+rm template
diff --git a/tls-cli.c b/tls-cli.c
new file mode 100644
index 000000000..15ad04435
--- /dev/null
+++ b/tls-cli.c
@@ -0,0 +1,167 @@
+/* This example code is placed in the public domain. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#define CHECK(x) assert((x) >= 0)
+
+#define MAX_BUF 1024
+#define MSG "Hello TLS"
+
+static int tcp_connect(void)
+{
+ const char * PORT = "5556";
+ const char * SERVER = "127.0.0.1";
+ int err, sd;
+ struct sockaddr_in sa;
+
+ /* connects to server
+ */
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset(&sa, '\0', sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(atoi(PORT));
+ inet_pton(AF_INET, SERVER, &sa.sin_addr);
+
+ err = connect(sd, (struct sockaddr *)&sa, sizeof(sa));
+ if (err < 0)
+ {
+ fprintf(stderr, "Connect error\n");
+ exit(1);
+ }
+
+ return sd;
+}
+
+static void tcp_close(int sd)
+{
+ shutdown(sd, SHUT_RDWR); /* no more receptions */
+ close(sd);
+}
+
+int main(void)
+{
+ int ret, sd, ii;
+ gnutls_session_t session;
+ char buffer[MAX_BUF + 1], *desc;
+ gnutls_datum_t out;
+ int type;
+ unsigned status;
+ gnutls_certificate_credentials_t xcred;
+
+ if (gnutls_check_version("3.4.6") == NULL)
+ {
+ fprintf(stderr, "GnuTLS 3.4.6 or later is required for this example\n");
+ exit(1);
+ }
+
+ /* for backwards compatibility with gnutls < 3.3.0 */
+ CHECK(gnutls_global_init());
+
+ /* X509 stuff */
+ CHECK(gnutls_certificate_allocate_credentials(&xcred));
+
+ gnutls_certificate_set_x509_key_file(xcred, "client-cert.pem", "client-key.pem", GNUTLS_X509_FMT_PEM);
+
+ CHECK(gnutls_certificate_set_x509_trust_file(xcred, "ca-cert.pem", GNUTLS_X509_FMT_PEM));
+
+ /* Initialize TLS session */
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT));
+
+ /* It is recommended to use the default priorities */
+ CHECK(gnutls_set_default_priority(session));
+
+ /* put the x509 credentials to the current session */
+ CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred));
+
+ sd = tcp_connect();
+
+ gnutls_transport_set_int(session, sd);
+ gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+
+ /* Perform the TLS handshake */
+ do
+ {
+ ret = gnutls_handshake(session);
+ } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
+ if (ret < 0)
+ {
+ if (ret == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR)
+ {
+ /* check certificate verification status */
+ type = gnutls_certificate_type_get(session);
+ status = gnutls_session_get_verify_cert_status(session);
+ CHECK(gnutls_certificate_verification_status_print(status, type, &out, 0));
+ printf("cert verify output: %s\n", out.data);
+ gnutls_free(out.data);
+ }
+ fprintf(stderr, "*** Handshake failed: %s\n", gnutls_strerror(ret));
+ goto end;
+ }
+ else
+ {
+ desc = gnutls_session_get_desc(session);
+ printf("- Session info: %s\n", desc);
+ gnutls_free(desc);
+ }
+
+ /* send data */
+ CHECK(gnutls_record_send(session, MSG, strlen(MSG)));
+
+ ret = gnutls_record_recv(session, buffer, MAX_BUF);
+ if (ret == 0)
+ {
+ printf("- Peer has closed the TLS connection\n");
+ goto end;
+ }
+ else if (ret < 0 && gnutls_error_is_fatal(ret) == 0)
+ {
+ fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
+ }
+ else if (ret < 0)
+ {
+ fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
+ goto end;
+ }
+
+ if (ret > 0)
+ {
+ printf("- Received %d bytes: ", ret);
+ for (ii = 0; ii < ret; ii++)
+ {
+ fputc(buffer[ii], stdout);
+ }
+ fputs("\n", stdout);
+ }
+
+ CHECK(gnutls_bye(session, GNUTLS_SHUT_RDWR));
+
+end:
+
+ tcp_close(sd);
+
+ gnutls_deinit(session);
+
+ gnutls_certificate_free_credentials(xcred);
+
+ gnutls_global_deinit();
+
+ return 0;
+}
diff --git a/tls-srv.c b/tls-srv.c
new file mode 100644
index 000000000..c6636d60a
--- /dev/null
+++ b/tls-srv.c
@@ -0,0 +1,146 @@
+/* This example code is placed in the public domain. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+#include <assert.h>
+
+#define CAFILE "ca-cert.pem"
+#define KEYFILE "server-key.pem"
+#define CERTFILE "server-cert.pem"
+#define CRLFILE "crl.pem"
+
+#define CHECK(x) assert((x) >= 0)
+#define LOOP_CHECK(rval, cmd) \
+ do \
+ { \
+ rval = cmd; \
+ } while (rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED)
+
+#define MAX_BUF 16
+#define PORT 5556 /* listen to 5556 port */
+
+int main(void)
+{
+ int listen_sd;
+ int sd, ret;
+ gnutls_certificate_credentials_t x509_cred;
+ gnutls_priority_t priority_cache;
+ struct sockaddr_in sa_serv;
+ struct sockaddr_in sa_cli;
+ socklen_t client_len;
+ char topbuf[512];
+ gnutls_session_t session;
+ char buffer[MAX_BUF + 1];
+ int optval = 1;
+
+ /* for backwards compatibility with gnutls < 3.3.0 */
+ CHECK(gnutls_global_init());
+
+ CHECK(gnutls_certificate_allocate_credentials(&x509_cred));
+ CHECK(gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM));
+ CHECK(gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM));
+ CHECK(gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE, GNUTLS_X509_FMT_PEM));
+ CHECK(gnutls_priority_init(&priority_cache, NULL, NULL));
+
+#if GNUTLS_VERSION_NUMBER >= 0x030506
+ /* only available since GnuTLS 3.5.6, on previous versions see
+ * gnutls_certificate_set_dh_params(). */
+ gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_HIGH);
+#endif
+
+ /* Socket operations */
+ listen_sd = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset(&sa_serv, '\0', sizeof(sa_serv));
+ sa_serv.sin_family = AF_INET;
+ sa_serv.sin_addr.s_addr = INADDR_ANY;
+ sa_serv.sin_port = htons(PORT); /* Server Port number */
+
+ setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int));
+ bind(listen_sd, (struct sockaddr *)&sa_serv, sizeof(sa_serv));
+ listen(listen_sd, 1024);
+
+ printf("Server ready. Listening to port '%d'.\n", PORT);
+
+ client_len = sizeof(sa_cli);
+ for (;;)
+ {
+ CHECK(gnutls_init(&session, GNUTLS_SERVER));
+ CHECK(gnutls_priority_set(session, priority_cache));
+ CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred));
+ gnutls_session_set_verify_cert(session, NULL, 0);
+ gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
+ gnutls_certificate_send_x509_rdn_sequence(session, 1);
+ gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+
+ sd = accept(listen_sd, (struct sockaddr *)&sa_cli, &client_len);
+
+ printf("- connection from %s, port %d\n",
+ inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)),
+ ntohs(sa_cli.sin_port));
+
+ gnutls_transport_set_int(session, sd);
+
+ LOOP_CHECK(ret, gnutls_handshake(session));
+ if (ret < 0)
+ {
+ close(sd);
+ gnutls_deinit(session);
+ fprintf(stderr, "*** Handshake has failed (%s)\n", gnutls_strerror(ret));
+ continue;
+ }
+ printf("- Handshake was completed\n");
+
+ for (;;)
+ {
+ LOOP_CHECK(ret, gnutls_record_recv(session, buffer, MAX_BUF));
+
+ if (ret == 0)
+ {
+ printf("- Peer has closed the GnuTLS connection\n");
+ break;
+ }
+ else if (ret < 0 && gnutls_error_is_fatal(ret) == 0)
+ {
+ fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
+ }
+ else if (ret < 0)
+ {
+ fprintf(stderr,
+ "\n*** Received corrupted "
+ "data(%d). Closing the connection.\n",
+ ret);
+ break;
+ }
+ else if (ret > 0 && ret < MAX_BUF - 1)
+ {
+ buffer[ret] = '$';
+ CHECK(gnutls_record_send(session, buffer, ret + 1));
+ }
+ }
+ LOOP_CHECK(ret, gnutls_bye(session, GNUTLS_SHUT_WR));
+
+ close(sd);
+ gnutls_deinit(session);
+ }
+ close(listen_sd);
+
+ gnutls_certificate_free_credentials(x509_cred);
+ gnutls_priority_deinit(priority_cache);
+
+ gnutls_global_deinit();
+
+ return 0;
+}