Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'gnutls_priority_override_option'
Signed-off-by: Daniel Lenski <dlenski@gmail.com>
  • Loading branch information
dlenski committed Mar 30, 2020
2 parents e4b2297 + 03dad77 commit 9354046
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 103 deletions.
2 changes: 0 additions & 2 deletions cstp.c
Expand Up @@ -637,8 +637,6 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
free_optlist(old_cstp_opts);
vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
vpn_progress(vpninfo, PRG_DEBUG, _("CSTP Ciphersuite: %s\n"),
openconnect_get_cstp_cipher(vpninfo));

monitor_fd_new(vpninfo, ssl);

Expand Down
7 changes: 2 additions & 5 deletions gnutls-dtls.c
Expand Up @@ -35,9 +35,6 @@
#include <gnutls/dtls.h>
#include "gnutls.h"

#if GNUTLS_VERSION_NUMBER < 0x030200
# define GNUTLS_DTLS1_2 202
#endif
#if GNUTLS_VERSION_NUMBER < 0x030400
# define GNUTLS_CIPHER_CHACHA20_POLY1305 23
#endif
Expand Down Expand Up @@ -121,7 +118,7 @@ void gather_dtls_ciphers(struct openconnect_info *vpninfo, struct oc_text_buf *b

buf_append(buf, "PSK-NEGOTIATE");

ret = gnutls_priority_init(&cache, vpninfo->gnutls_prio, NULL);
ret = gnutls_priority_init(&cache, vpninfo->ciphersuite_config, NULL);
if (ret < 0) {
buf->error = -EIO;
return;
Expand Down Expand Up @@ -192,7 +189,7 @@ static int start_dtls_psk_handshake(struct openconnect_info *vpninfo, int dtls_f
}

prio = buf_alloc();
buf_append(prio, "%s:-VERS-TLS-ALL:+VERS-DTLS-ALL:-KX-ALL:+PSK", vpninfo->gnutls_prio);
buf_append(prio, "%s:-VERS-TLS-ALL:+VERS-DTLS-ALL:-KX-ALL:+PSK", vpninfo->ciphersuite_config);
if (buf_error(prio)) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to generate DTLS priority string\n"));
Expand Down
99 changes: 33 additions & 66 deletions gnutls.c
Expand Up @@ -75,6 +75,17 @@ static int gnutls_pin_callback(void *priv, int attempt, const char *uri,
(GNUTLS_VERSION_NUMBER >= ( ((a) << 16) + ((b) << 8) + (c) ) || \
gnutls_check_version(#a "." #b "." #c)))

static char tls_library_version[32] = "";

const char *openconnect_get_tls_library_version()
{
if (!*tls_library_version) {
snprintf(tls_library_version, sizeof(tls_library_version), "GnuTLS %s",
gnutls_check_version(NULL));
}
return tls_library_version;
}

/* Helper functions for reading/writing lines over SSL. */
static int _openconnect_gnutls_write(gnutls_session_t ses, int fd, struct openconnect_info *vpninfo, char *buf, size_t len)
{
Expand Down Expand Up @@ -526,33 +537,6 @@ static int load_pkcs12_certificate(struct openconnect_info *vpninfo,
return 0;
}

/* Older versions of GnuTLS didn't actually bother to check this, so we'll
do it for them. Is there a bug reference for this? Or just the git commit
reference (c1ef7efb in master, 5196786c in gnutls_3_0_x-2)? */
static int check_issuer_sanity(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer)
{
#if GNUTLS_VERSION_NUMBER > 0x030014
return 0;
#else
unsigned char id1[512], id2[512];
size_t id1_size = 512, id2_size = 512;
int err;

err = gnutls_x509_crt_get_authority_key_id(cert, id1, &id1_size, NULL);
if (err)
return 0;

err = gnutls_x509_crt_get_subject_key_id(issuer, id2, &id2_size, NULL);
if (err)
return 0;
if (id1_size == id2_size && !memcmp(id1, id2, id1_size))
return 0;

/* EEP! */
return -EIO;
#endif
}

static int count_x509_certificates(gnutls_datum_t *datum)
{
int count = 0;
Expand Down Expand Up @@ -1613,8 +1597,7 @@ static int load_certificate(struct openconnect_info *vpninfo)

for (i = 0; i < nr_extra_certs; i++) {
if (extra_certs[i] &&
gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]) &&
!check_issuer_sanity(last_cert, extra_certs[i]))
gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]))
break;
}

Expand All @@ -1627,16 +1610,6 @@ static int load_certificate(struct openconnect_info *vpninfo)
/* Look for it in the system trust cafile too. */
err = gnutls_certificate_get_issuer(vpninfo->https_cred,
last_cert, &issuer, 0);
/* The check_issuer_sanity() function works fine as a workaround where
it was used above, but when gnutls_certificate_get_issuer() returns
a bogus cert, there's nothing we can do to fix it up. We don't get
to iterate over all the available certs like we can over our own
list. */
if (!err && check_issuer_sanity(last_cert, issuer)) {
vpn_progress(vpninfo, PRG_ERR,
_("WARNING: GnuTLS returned incorrect issuer certs; authentication may fail!\n"));
break;
}
free_issuer = 0;

#ifdef HAVE_P11KIT
Expand Down Expand Up @@ -2230,24 +2203,26 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
* 28065ce3896b1b0f87972d0bce9b17641ebb69b9
*/

if (!strlen(vpninfo->ciphersuite_config)) {
#ifdef DEFAULT_PRIO
default_prio = DEFAULT_PRIO ":%COMPAT";
default_prio = DEFAULT_PRIO ":%COMPAT";
#else
/* GnuTLS 3.5.19 and onward refuse to negotiate AES-CBC-HMAC-SHA256
* by default but some Cisco servers can't do anything better, so
* explicitly add '+SHA256' to allow it. Yay Cisco. */
default_prio = "NORMAL:-VERS-SSL3.0:+SHA256:%COMPAT";
/* GnuTLS 3.5.19 and onward refuse to negotiate AES-CBC-HMAC-SHA256
* by default but some Cisco servers can't do anything better, so
* explicitly add '+SHA256' to allow it. Yay Cisco. */
default_prio = "NORMAL:-VERS-SSL3.0:+SHA256:%COMPAT";
#endif

snprintf(vpninfo->gnutls_prio, sizeof(vpninfo->gnutls_prio), "%s%s%s",
default_prio, vpninfo->pfs?":-RSA":"", vpninfo->no_tls13?":-VERS-TLS1.3":"");
snprintf(vpninfo->ciphersuite_config, sizeof(vpninfo->ciphersuite_config), "%s%s%s",
default_prio, vpninfo->pfs?":-RSA":"", vpninfo->no_tls13?":-VERS-TLS1.3":"");
}

err = gnutls_priority_set_direct(vpninfo->https_sess,
vpninfo->gnutls_prio, NULL);
vpninfo->ciphersuite_config, NULL);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to set TLS priority string (\"%s\"): %s\n"),
vpninfo->gnutls_prio, gnutls_strerror(err));
_("Failed to set GnuTLS priority string (\"%s\"): %s\n"),
vpninfo->ciphersuite_config, gnutls_strerror(err));
gnutls_deinit(vpninfo->https_sess);
vpninfo->https_sess = NULL;
closesocket(ssl_sock);
Expand All @@ -2270,9 +2245,6 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
if (err)
return err;

gnutls_free(vpninfo->cstp_cipher);
vpninfo->cstp_cipher = get_gnutls_cipher(vpninfo->https_sess);

vpninfo->ssl_fd = ssl_sock;

vpninfo->ssl_read = openconnect_gnutls_read;
Expand Down Expand Up @@ -2330,12 +2302,15 @@ int cstp_handshake(struct openconnect_info *vpninfo, unsigned init)
}
}

gnutls_free(vpninfo->cstp_cipher);
vpninfo->cstp_cipher = get_gnutls_cipher(vpninfo->https_sess);

if (init) {
vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
vpninfo->hostname);
vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s with ciphersuite %s\n"),
vpninfo->hostname, vpninfo->cstp_cipher);
} else {
vpn_progress(vpninfo, PRG_INFO, _("Renegotiated SSL on %s\n"),
vpninfo->hostname);
vpn_progress(vpninfo, PRG_INFO, _("Renegotiated SSL on %s with ciphersuite %s\n"),
vpninfo->hostname, vpninfo->cstp_cipher);
}

return 0;
Expand Down Expand Up @@ -2381,15 +2356,7 @@ int openconnect_init_ssl(void)

char *get_gnutls_cipher(gnutls_session_t session)
{
char *str;
#if GNUTLS_VERSION_NUMBER > 0x03010a
str = gnutls_session_get_desc(session);
#else
str = gnutls_strdup(gnutls_cipher_suite_get_name(
gnutls_kx_get(session), gnutls_cipher_get(session),
gnutls_mac_get(session)));
#endif
return str;
return gnutls_session_get_desc(session);
}

int openconnect_sha1(unsigned char *result, void *data, int datalen)
Expand Down Expand Up @@ -2657,7 +2624,7 @@ void *establish_eap_ttls(struct openconnect_info *vpninfo)
gnutls_credentials_set(ttls_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);

err = gnutls_priority_set_direct(ttls_sess,
vpninfo->gnutls_prio, NULL);
vpninfo->ciphersuite_config, NULL);

err = gnutls_handshake(ttls_sess);
if (!err) {
Expand Down
1 change: 1 addition & 0 deletions libopenconnect.map.in
Expand Up @@ -110,6 +110,7 @@ OPENCONNECT_5_6 {

OPENCONNECT_PRIVATE {
global: @SYMVER_TIME@ @SYMVER_GETLINE@ @SYMVER_JAVA@ @SYMVER_ASPRINTF@ @SYMVER_VASPRINTF@ @SYMVER_WIN32_STRERROR@
openconnect_get_tls_library_version;
openconnect_fopen_utf8;
openconnect_open_utf8;
openconnect_sha1;
Expand Down
36 changes: 23 additions & 13 deletions library.c
Expand Up @@ -389,13 +389,19 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
free(vpninfo->ifname);
free(vpninfo->dtls_cipher);
free(vpninfo->peer_cert_hash);
#if defined(OPENCONNECT_OPENSSL) && defined (HAVE_BIO_METH_FREE)
#if defined(OPENCONNECT_OPENSSL)
free(vpninfo->cstp_cipher);
#if defined(HAVE_BIO_METH_FREE)
if (vpninfo->ttls_bio_meth)
BIO_meth_free(vpninfo->ttls_bio_meth);
#endif
#ifdef HAVE_DTLS
free(vpninfo->dtls_cipher_desc);
#endif
#elif defined(OPENCONNECT_GNUTLS)
gnutls_free(vpninfo->cstp_cipher); /* In OpenSSL this is const */
gnutls_free(vpninfo->cstp_cipher);
#ifdef HAVE_DTLS
gnutls_free(vpninfo->gnutls_dtls_cipher);
gnutls_free(vpninfo->dtls_cipher_desc);
#endif
#endif
free(vpninfo->dtls_addr);
Expand Down Expand Up @@ -1010,23 +1016,27 @@ const char *openconnect_get_dtls_compression(struct openconnect_info * vpninfo)

const char *openconnect_get_dtls_cipher(struct openconnect_info *vpninfo)
{
if (vpninfo->dtls_state != DTLS_CONNECTED || !vpninfo->dtls_ssl) {
#if defined(OPENCONNECT_GNUTLS)
if (vpninfo->dtls_state != DTLS_CONNECTED) {
gnutls_free(vpninfo->gnutls_dtls_cipher);
vpninfo->gnutls_dtls_cipher = NULL;
gnutls_free(vpninfo->dtls_cipher_desc);
#else
free(vpninfo->dtls_cipher_desc);
#endif
vpninfo->dtls_cipher_desc = NULL;
return NULL;
}
/* in DTLS rehandshakes don't switch the ciphersuite as only
* one is enabled. */
if (vpninfo->gnutls_dtls_cipher == NULL)
vpninfo->gnutls_dtls_cipher = get_gnutls_cipher(vpninfo->dtls_ssl);
return vpninfo->gnutls_dtls_cipher;
if (vpninfo->dtls_cipher_desc == NULL) {
#if defined(OPENCONNECT_GNUTLS)
vpninfo->dtls_cipher_desc = get_gnutls_cipher(vpninfo->dtls_ssl);
#else
if (vpninfo->dtls_ssl)
return SSL_get_cipher(vpninfo->dtls_ssl);
else
return NULL;
if (asprintf(&vpninfo->dtls_cipher_desc, "%s-%s",
SSL_get_version(vpninfo->dtls_ssl), SSL_get_cipher_name(vpninfo->dtls_ssl)) < 0)
return NULL;
#endif
}
return vpninfo->dtls_cipher_desc;
}

int openconnect_set_csd_environ(struct openconnect_info *vpninfo,
Expand Down
23 changes: 18 additions & 5 deletions main.c
Expand Up @@ -156,6 +156,7 @@ enum {
OPT_COOKIE_ON_STDIN,
OPT_CSD_USER,
OPT_CSD_WRAPPER,
OPT_CIPHERSUITES,
OPT_DISABLE_IPV6,
OPT_DTLS_CIPHERS,
OPT_DTLS12_CIPHERS,
Expand Down Expand Up @@ -280,6 +281,9 @@ static const struct option long_options[] = {
OPTION("form-entry", 1, 'F'),
#ifdef OPENCONNECT_GNUTLS
OPTION("gnutls-debug", 1, OPT_GNUTLS_DEBUG),
OPTION("gnutls-priority", 1, OPT_CIPHERSUITES),
#elif defined(OPENCONNECT_OPENSSL)
OPTION("openssl-ciphers", 1, OPT_CIPHERSUITES),
#endif
OPTION(NULL, 0, 0)
};
Expand Down Expand Up @@ -596,11 +600,7 @@ static void print_build_opts(void)
{
const char *comma = ", ", *sep = comma + 1;

#if defined(OPENCONNECT_OPENSSL)
printf(_("Using OpenSSL. Features present:"));
#elif defined(OPENCONNECT_GNUTLS)
printf(_("Using GnuTLS. Features present:"));
#endif
printf(_("Using %s. Features present:"), openconnect_get_tls_library_version());

if (openconnect_has_tss_blob_support()) {
printf("%sTPM", sep);
Expand Down Expand Up @@ -1505,6 +1505,19 @@ int main(int argc, char **argv)
gnutls_global_set_log_function(oc_gnutls_log_func);
break;
#endif
case OPT_CIPHERSUITES:
fprintf(stderr,
#ifdef OPENCONNECT_GNUTLS
_("WARNING: You specified --gnutls-priority. This should not be\n"
" necessary; please report cases where a priority string\n"
#elif defined(OPENCONNECT_OPENSSL)
_("WARNING: You specified --openssl-ciphers. This should not be\n"
" necessary; please report cases where a cipher list\n"
#endif
" override is necessary to connect to a server\n"
" to <openconnect-devel@lists.infradead.org>.\n"));
strncpy(vpninfo->ciphersuite_config, config_arg, sizeof(vpninfo->ciphersuite_config) - 1);
break;
default:
usage();
}
Expand Down
12 changes: 7 additions & 5 deletions openconnect-internal.h
Expand Up @@ -523,14 +523,14 @@ struct openconnect_info {
gnutls_certificate_credentials_t https_cred;
gnutls_psk_client_credentials_t psk_cred;
char local_cert_md5[MD5_SIZE * 2 + 1]; /* For CSD */
char gnutls_prio[256];
#ifdef HAVE_TROUSERS
struct oc_tpm1_ctx *tpm1;
#endif
#ifdef HAVE_TSS2
struct oc_tpm2_ctx *tpm2;
#endif
#endif /* OPENCONNECT_GNUTLS */
char ciphersuite_config[256];
struct oc_text_buf *ttls_pushbuf;
uint8_t ttls_eap_ident;
unsigned char *ttls_recvbuf;
Expand Down Expand Up @@ -573,9 +573,9 @@ struct openconnect_info {
NULL or not or pass it to DTLS_SEND/DTLS_RECV. This way we
have fewer ifdefs and accessor macros for it. */
gnutls_session_t dtls_ssl;
char *gnutls_dtls_cipher; /* cached for openconnect_get_dtls_cipher() */
#endif
char *cstp_cipher;
char *cstp_cipher; /* library-dependent description of TLS cipher */
char *dtls_cipher_desc; /* library-dependent description of DTLS cipher, cached for openconnect_get_dtls_cipher() */

int dtls_state;
int dtls_need_reconnect;
Expand All @@ -587,8 +587,9 @@ struct openconnect_info {

uint32_t ift_seq;

int cisco_dtls12;
char *dtls_cipher;
int cisco_dtls12; /* If Cisco server sent X-DTLS12-CipherSuite header, rather than X-DTLS-CipherSuite */
char *dtls_cipher; /* Value of aforementioned header (PSK-NEGOTIATE, or an OpenSSL cipher name) */

char *vpnc_script;
#ifndef _WIN32
int uid_csd_given;
Expand Down Expand Up @@ -997,6 +998,7 @@ int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct
int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt, int crypt_len);

/* {gnutls,openssl}.c */
const char *openconnect_get_tls_library_version();
int ssl_nonblock_read(struct openconnect_info *vpninfo, void *buf, int maxlen);
int ssl_nonblock_write(struct openconnect_info *vpninfo, void *buf, int buflen);
int openconnect_open_https(struct openconnect_info *vpninfo);
Expand Down
4 changes: 2 additions & 2 deletions openssl-dtls.c
Expand Up @@ -603,8 +603,8 @@ int dtls_try_handshake(struct openconnect_info *vpninfo)

vpninfo->dtls_state = DTLS_CONNECTED;
vpn_progress(vpninfo, PRG_INFO,
_("Established DTLS connection (using OpenSSL). Ciphersuite %s.\n"),
SSL_get_cipher(vpninfo->dtls_ssl));
_("Established DTLS connection (using OpenSSL). Ciphersuite %s-%s.\n"),
SSL_get_version(vpninfo->dtls_ssl), SSL_get_cipher(vpninfo->dtls_ssl));

c = openconnect_get_dtls_compression(vpninfo);
if (c) {
Expand Down

0 comments on commit 9354046

Please sign in to comment.