fi
AM_CONDITIONAL(USE_NLS, [test "$USE_NLS" = "yes"])
+# We will use GnuTLS if it's requested, and if GnuTLS doesn't have DTLS
+# support then we'll *also* use OpenSSL for that, but it appears *only*
+# only in the openconnect executable and not the library (hence shouldn't
+# be a problem for GPL'd programs using libopenconnect).
+#
+# If built with --with-gnutls --without-openssl then we'll even eschew
+# OpenSSL for DTLS support and will build without any DTLS support at all
+# if GnuTLS cannot manage.
+#
+# The default (for now) is to use OpenSSL for everything.
+
AC_ARG_WITH([gnutls],
AS_HELP_STRING([--with-gnutls],
[Use GnuTLS instead of OpenSSL (EXPERIMENTAL)]))
[Location of OpenSSL build dir]))
ssl_library=
-if test "$with_gnutls" = "yes" || test "$with_gnutls" = "shibboleet"; then
- if test "$with_openssl" != "no" && test "$with_openssl" != ""; then
- AC_MSG_ERROR([Cannot use both OpenSSL and GnuTLS simultaneously])
- fi
+if test "$with_gnutls" = "yes"; then
PKG_CHECK_MODULES(GNUTLS, gnutls)
if ! $PKG_CONFIG --atleast-version=2.12.16 gnutls; then
AC_MSG_ERROR([Your GnuTLS is too old. At least v2.12.16 is required])
fi
- with_openssl=no
- ssl_library=gnutls
oldlibs="$LIBS"
LIBS="$LIBS $GNUTLS_LIBS"
AC_CHECK_FUNC(gnutls_certificate_set_x509_system_trust,
[AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST, 1)], [])
AC_CHECK_FUNC(gnutls_pkcs12_simple_parse,
[AC_DEFINE(HAVE_GNUTLS_PKCS12_SIMPLE_PARSE, 1)], [])
- AC_CHECK_FUNC(gnutls_session_set_premaster,
- [AC_DEFINE(HAVE_GNUTLS_SESSION_SET_PREMASTER, 1)], [])
+ if test "$with_openssl" != "" || test "$with_openssl" = "no"; then
+ AC_CHECK_FUNC(gnutls_session_set_premaster,
+ [have_gnutls_dtls=yes], [have_gnutls_dtls=no])
+ else
+ have_gnutls_dtls=no
+ fi
+ if test "$have_gnutls_dtls" = "yes"; then
+ if test "$with_openssl" = "" || test "$with_openssl" = "no"; then
+ # They either said no OpenSSL or didn't specify, and GnuTLS can
+ # do DTLS, so just use GnuTLS.
+ AC_DEFINE(HAVE_GNUTLS_SESSION_SET_PREMASTER, 1)
+ ssl_library=gnutls
+ with_openssl=no
+ else
+ # They specifically asked for OpenSSL, so use it for DTLS even
+ # though GnuTLS could manage.
+ ssl_library=both
+ fi
+ else
+ if test "$with_openssl" = "no"; then
+ # GnuTLS doesn't have DTLS, but they don't want OpenSSL. So build
+ # without DTLS support at all.
+ ssl_library=gnutls
+ else
+ # GnuTLS doesn't have DTLS so use OpenSSL for it, but GnuTLS for
+ # the TCP connection (and thus in the library).
+ ssl_library=both
+ fi
+ fi
AC_CHECK_FUNC(gnutls_pkcs11_add_provider,
[PKG_CHECK_MODULES(P11KIT, p11-kit-1, [AC_DEFINE(HAVE_P11KIT)
AC_SUBST(P11KIT_PC, p11-kit-1)], [:])], [])
elif test "$with_gnutls" != "" && test "$with_gnutls" != "no"; then
AC_MSG_ERROR([Values other than 'yes' or 'no' for --with-gnutls are not supported])
fi
-
-if test "$with_openssl" = "yes" || test "$with_openssl" = "" ; then
+if test "$with_openssl" = "yes" || test "$with_openssl" = "" || test "$ssl_library" = "both"; then
PKG_CHECK_MODULES(OPENSSL, openssl, [],
[oldLIBS="$LIBS"
LIBS="$LIBS -lssl -lcrypto"
AC_SUBST([OPENSSL_LIBS], ["-lssl -lcrypto"])
AC_SUBST([OPENSSL_CFLAGS], [])],
[AC_MSG_RESULT(no)
- AC_ERROR([Could not build against OpenSSL])])
+ if test "$ssl_library" = "both"; then
+ ssl_library="gnutls";
+ else
+ AC_ERROR([Could not build against OpenSSL]);
+ fi])
LIBS="$oldLIBS"])
- ssl_library=openssl
+ if test "$ssl_library" != "both" && test "$ssl_library" != "gnutls"; then
+ ssl_library=openssl
+ fi
elif test "$with_openssl" != "no" ; then
OPENSSL_CFLAGS="-I${with_openssl}/include"
OPENSSL_LIBS="${with_openssl}/libssl.a ${with_openssl}/libcrypto.a -ldl -lz"
AC_SUBST(OPENSSL_LIBS)
enable_static=yes
enable_shared=no
- ssl_library=openssl
+ AC_DEFINE(DTLS_OPENSSL, 1)
+ if test "$ssl_library" != "both"; then
+ ssl_library=openssl
+ fi
fi
case "$ssl_library" in
gnutls)
AC_DEFINE(OPENCONNECT_GNUTLS, 1)
- AC_SUBST(SSL_LIBS, [$GNUTLS_LIBS])
- AC_SUBST(SSL_CFLAGS, [$GNUTLS_CFLAGS])
+ AC_DEFINE(DTLS_GNUTLS, 1)
+ AC_SUBST(SSL_LIBRARY, [gnutls])
+ AC_SUBST(SSL_LIBS, ['$(GNUTLS_LIBS)'])
+ AC_SUBST(SSL_CFLAGS, ['$(GNUTLS_CFLAGS)'])
;;
openssl)
AC_DEFINE(OPENCONNECT_OPENSSL, 1)
- AC_SUBST(SSL_LIBS, [$OPENSSL_LIBS])
- AC_SUBST(SSL_CFLAGS, [$OPENSSL_CFLAGS])
+ AC_DEFINE(DTLS_OPENSSL, 1)
+ AC_SUBST(SSL_LIBRARY, [openssl])
+ AC_SUBST(SSL_LIBS, ['$(OPENSSL_LIBS)'])
+ AC_SUBST(SSL_CFLAGS, ['$(OPENSSL_CFLAGS)'])
+ ;;
+ both)
+ # GnuTLS for TCP, OpenSSL for DTLS
+ AC_DEFINE(OPENCONNECT_GNUTLS, 1)
+ AC_DEFINE(DTLS_OPENSSL, 1)
+ AC_SUBST(SSL_LIBRARY, [gnutls])
+ AC_SUBST(SSL_LIBS, ['$(GNUTLS_LIBS)'])
+ AC_SUBST(SSL_CFLAGS, ['$(GNUTLS_CFLAGS)'])
+ AC_SUBST(DTLS_SSL_LIBS, ['$(OPENSSL_LIBS)'])
+ AC_SUBST(DTLS_SSL_CFLAGS, ['$(OPENSSL_CFLAGS)'])
;;
*)
AC_MSG_ERROR([Neither OpenSSL nor GnuTLS selected for SSL.])
;;
esac
-AC_SUBST(SSL_LIBRARY, $ssl_library)
# Needs to happen after we default to static/shared libraries based on OpenSSL
AC_PROG_LIBTOOL
[AC_CHECK_HEADER([net/tun/if_tun.h],
[AC_DEFINE([IF_TUN_HDR], ["net/tun/if_tun.h"])])])])])
-if test "${ssl_library}" = "openssl"; then
+if test "$ssl_library" = "openssl" || test "$ssl_library" = "both"; then
oldLIBS="$LIBS"
LIBS="$LIBS $OPENSSL_LIBS"
- AC_MSG_CHECKING([for ENGINE_by_id() in OpenSSL])
- AC_LINK_IFELSE([AC_LANG_PROGRAM(
- [#include <openssl/engine.h>],
- [ENGINE_by_id("foo");])],
- [AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_ENGINE, [1], [OpenSSL has ENGINE support])],
- [AC_MSG_RESULT(no)
- AC_MSG_NOTICE([Building without OpenSSL TPM ENGINE support])])
+ if test "$ssl_library" = "openssl"; then
+ AC_MSG_CHECKING([for ENGINE_by_id() in OpenSSL])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <openssl/engine.h>],
+ [ENGINE_by_id("foo");])],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ENGINE, [1], [OpenSSL has ENGINE support])],
+ [AC_MSG_RESULT(no)
+ AC_MSG_NOTICE([Building without OpenSSL TPM ENGINE support])])
+ fi
AC_MSG_CHECKING([for dtls1_stop_timer() in OpenSSL])
- AC_LINK_IFELSE([AC_LANG_PROGRAM(
- [#include <openssl/ssl.h>
- #include <stdlib.h>
- extern void dtls1_stop_timer(SSL *);],
- [dtls1_stop_timer(NULL);])],
- [AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_DTLS1_STOP_TIMER, [1], [OpenSSL has dtls1_stop_timer() function])],
- [AC_MSG_RESULT(no)])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <openssl/ssl.h>
+ #include <stdlib.h>
+ extern void dtls1_stop_timer(SSL *);],
+ [dtls1_stop_timer(NULL);])],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_DTLS1_STOP_TIMER, [1], [OpenSSL has dtls1_stop_timer() function])],
+ [AC_MSG_RESULT(no)])
LIBS="$oldLIBS"
fi
#include <netinet/in.h>
#include <fcntl.h>
#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
#include "openconnect-internal.h"
* their clients use anyway.
*/
-#if defined (OPENCONNECT_OPENSSL)
+#if defined (DTLS_OPENSSL)
#define DTLS_SEND SSL_write
#define DTLS_RECV SSL_read
static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
if (!vpninfo->dtls_ctx) {
vpn_progress(vpninfo, PRG_ERR,
_("Initialise DTLSv1 CTX failed\n"));
+ openconnect_report_ssl_errors(vpninfo);
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
if (ret == 1) {
- vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
+ vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection (using OpenSSL)\n"));
if (vpninfo->dtls_ssl) {
/* We are replacing an old connection */
return -EINVAL;
}
-#elif defined (OPENCONNECT_GNUTLS)
+#elif defined (DTLS_GNUTLS)
struct {
const char *name;
gnutls_cipher_algorithm_t cipher;
int err = gnutls_handshake(vpninfo->new_dtls_ssl);
if (!err) {
- vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
+ vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection (using GnuTLS)\n"));
if (vpninfo->dtls_ssl) {
/* We are replacing an old connection */
static int dtls_restart(struct openconnect_info *vpninfo)
{
if (vpninfo->dtls_ssl) {
-#if defined (OPENCONNECT_OPENSSL)
+#if defined (DTLS_OPENSSL)
SSL_free(vpninfo->dtls_ssl);
-#elif defined (OPENCONNECT_GNUTLS)
+#elif defined (DTLS_GNUTLS)
gnutls_deinit(vpninfo->dtls_ssl);
#endif
close(vpninfo->dtls_fd);
struct vpn_option *dtls_opt = vpninfo->dtls_options;
int dtls_port = 0;
+#if defined (OPENCONNECT_GNUTLS) && defined (DTLS_OPENSSL)
+ /* If we're using GnuTLS for authentication but OpenSSL for DTLS,
+ we'll need to initialise OpenSSL now... */
+ SSL_library_init ();
+ ERR_clear_error ();
+ SSL_load_error_strings ();
+ OpenSSL_add_all_algorithms ();
+#endif
+
while (dtls_opt) {
vpn_progress(vpninfo, PRG_TRACE,
_("DTLS option %s : %s\n"),
/* One byte of header */
this->hdr[7] = AC_PKT_DATA;
-#if defined(OPENCONNECT_OPENSSL)
+#if defined(DTLS_OPENSSL)
ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
if (ret <= 0) {
ret = SSL_get_error(vpninfo->dtls_ssl, ret);
}
return 1;
}
-#elif defined (OPENCONNECT_GNUTLS)
+#elif defined (DTLS_GNUTLS)
ret = gnutls_record_send(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
if (ret <= 0) {
if (ret != GNUTLS_E_AGAIN) {
#include "openconnect.h"
-#if defined (OPENCONNECT_OPENSSL)
+#if defined (OPENCONNECT_OPENSSL) || defined(DTLS_OPENSSL)
#include <openssl/ssl.h>
-#elif defined (OPENCONNECT_GNUTLS)
+#include <openssl/err.h>
+#endif
+#if defined (OPENCONNECT_GNUTLS)
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#endif
int reconnect_interval;
int dtls_attempt_period;
time_t new_dtls_started;
-#if defined(OPENCONNECT_OPENSSL)
+#if defined(DTLS_OPENSSL)
SSL_CTX *dtls_ctx;
SSL *dtls_ssl;
SSL *new_dtls_ssl;
SSL_SESSION *dtls_session;
-#elif defined(OPENCONNECT_GNUTLS)
+#elif defined(DTLS_GNUTLS)
/* Call these *_ssl rather than *_sess because they're just
pointers, and generic code (in mainloop.c for example)
wants to check if they're NULL or not. No point in being
openconnect_progress_vfn progress;
};
-#if (defined (OPENCONNECT_OPENSSL) && defined (SSL_OP_CISCO_ANYCONNECT)) || \
- (defined(OPENCONNECT_GNUTLS) && defined (HAVE_GNUTLS_SESSION_SET_PREMASTER))
+#if (defined (DTLS_OPENSSL) && defined (SSL_OP_CISCO_ANYCONNECT)) || \
+ (defined (DTLS_GNUTLS) && defined (HAVE_GNUTLS_SESSION_SET_PREMASTER))
#define HAVE_DTLS 1
#endif
#define AC_PKT_TERM_SERVER 9 /* Server kick */
/* Ick */
+#ifdef DTLS_OPENSSL
#if OPENSSL_VERSION_NUMBER >= 0x00909000L
#define method_const const
#else
#define method_const
#endif
+#endif
#define vpn_progress(vpninfo, ...) (vpninfo)->progress ((vpninfo)->cbdata, __VA_ARGS__)
char **response, const char *fmt, ...);
int __attribute__ ((format (printf, 2, 3)))
openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...);
+#if defined(OPENCONNECT_OPENSSL) || defined (DTLS_OPENSSL)
+void openconnect_report_ssl_errors(struct openconnect_info *vpninfo);
+#endif
/* ${SSL_LIBRARY}.c */
int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len);
void openconnect_close_https(struct openconnect_info *vpninfo, int final);
int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, OPENCONNECT_X509 *cert,
char *buf);
-/* This one is actually OpenSSL-specific */
-void openconnect_report_ssl_errors(struct openconnect_info *vpninfo);
int openconnect_sha1(unsigned char *result, void *data, int len);
int openconnect_random(void *bytes, int len);
int openconnect_local_cert_md5(struct openconnect_info *vpninfo,