From 4892c7a53bb0adec98c4540a0b127b209625f82a Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 4 Mar 2015 10:29:06 +0100 Subject: [PATCH 2/2] when using gnutls enable only the DTLS ciphersuites that were available during TLS Signed-off-by: Nikos Mavrogiannopoulos --- cstp.c | 3 ++ dtls.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++---- gnutls.c | 7 ++--- openconnect-internal.h | 2 ++ 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/cstp.c b/cstp.c index d0d7eff..a06ca34 100644 --- a/cstp.c +++ b/cstp.c @@ -202,6 +202,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) vpninfo->ip_info.domain = vpninfo->ip_info.proxy_pac = NULL; vpninfo->banner = NULL; + if (!vpninfo->dtls_ciphers) + vpninfo->dtls_ciphers = dtls_ciphers_from_conn(vpninfo); + for (i = 0; i < 3; i++) vpninfo->ip_info.dns[i] = vpninfo->ip_info.nbns[i] = NULL; free_split_routes(vpninfo); diff --git a/dtls.c b/dtls.c index abffbf1..6ac537d 100644 --- a/dtls.c +++ b/dtls.c @@ -222,6 +222,11 @@ static SSL_SESSION *generate_dtls_session(struct openconnect_info *vpninfo, } #endif +char *dtls_ciphers_from_conn(struct openconnect_info *vpninfo) +{ + return NULL; +} + static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd) { STACK_OF(SSL_CIPHER) *ciphers; @@ -438,27 +443,89 @@ void dtls_shutdown(struct openconnect_info *vpninfo) #include #include "gnutls.h" +#define SSTR(x) x,sizeof(x) struct { const char *name; + unsigned name_len; gnutls_protocol_t version; gnutls_cipher_algorithm_t cipher; gnutls_mac_algorithm_t mac; const char *prio; + unsigned disabled; } gnutls_dtls_ciphers[] = { - { "AES128-SHA", GNUTLS_DTLS0_9, GNUTLS_CIPHER_AES_128_CBC, GNUTLS_MAC_SHA1, + { SSTR("AES128-SHA"), GNUTLS_DTLS0_9, GNUTLS_CIPHER_AES_128_CBC, GNUTLS_MAC_SHA1, "NONE:+VERS-DTLS0.9:+COMP-NULL:+AES-128-CBC:+SHA1:+RSA:%COMPAT" }, - { "AES256-SHA", GNUTLS_DTLS0_9, GNUTLS_CIPHER_AES_256_CBC, GNUTLS_MAC_SHA1, + { SSTR("AES256-SHA"), GNUTLS_DTLS0_9, GNUTLS_CIPHER_AES_256_CBC, GNUTLS_MAC_SHA1, "NONE:+VERS-DTLS0.9:+COMP-NULL:+AES-256-CBC:+SHA1:+RSA:%COMPAT" }, - { "DES-CBC3-SHA", GNUTLS_DTLS0_9, GNUTLS_CIPHER_3DES_CBC, GNUTLS_MAC_SHA1, + { SSTR("DES-CBC3-SHA"), GNUTLS_DTLS0_9, GNUTLS_CIPHER_3DES_CBC, GNUTLS_MAC_SHA1, "NONE:+VERS-DTLS0.9:+COMP-NULL:+3DES-CBC:+SHA1:+RSA:%COMPAT" }, #if GNUTLS_VERSION_NUMBER >= 0x030207 /* if DTLS 1.2 is supported (and a bug in gnutls is solved) */ - { "OC-DTLS1_2-AES128-GCM", GNUTLS_DTLS1_2, GNUTLS_CIPHER_AES_128_GCM, GNUTLS_MAC_AEAD, + { SSTR("OC-DTLS1_2-AES128-GCM"), GNUTLS_DTLS1_2, GNUTLS_CIPHER_AES_128_GCM, GNUTLS_MAC_AEAD, "NONE:+VERS-DTLS1.2:+COMP-NULL:+AES-128-GCM:+AEAD:+RSA:%COMPAT:+SIGN-ALL" }, - { "OC-DTLS1_2-AES256-GCM", GNUTLS_DTLS1_2, GNUTLS_CIPHER_AES_256_GCM, GNUTLS_MAC_AEAD, + { SSTR("OC-DTLS1_2-AES256-GCM"), GNUTLS_DTLS1_2, GNUTLS_CIPHER_AES_256_GCM, GNUTLS_MAC_AEAD, "NONE:+VERS-DTLS1.2:+COMP-NULL:+AES-256-GCM:+AEAD:+RSA:%COMPAT:+SIGN-ALL" }, #endif }; +char *dtls_ciphers_from_conn(struct openconnect_info *vpninfo) +{ + /* only enable the ciphers that would have been negotiated in the TLS channel */ + unsigned i, j; + int ret; + unsigned idx; + gnutls_cipher_algorithm_t cipher; + gnutls_mac_algorithm_t mac; + struct oc_text_buf *buf; + gnutls_priority_t cache; + char *p; + + /* everything is disabled by default */ + for (i = 0; i < sizeof(gnutls_dtls_ciphers)/sizeof(gnutls_dtls_ciphers[0]); i++) { + gnutls_dtls_ciphers[i].disabled = 1; + } + + ret = gnutls_priority_init(&cache, vpninfo->gnutls_default_prio, NULL); + if (ret < 0) + return NULL; + + for (j=0;;j++) { + ret = gnutls_priority_get_cipher_suite_index(cache, j, &idx); + if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE) + continue; + else if (ret < 0) + break; + + if (gnutls_cipher_suite_info(idx, NULL, NULL, &cipher, &mac, NULL) != NULL) { + for (i = 0; i < sizeof(gnutls_dtls_ciphers)/sizeof(gnutls_dtls_ciphers[0]); i++) { + if (gnutls_dtls_ciphers[i].mac == mac && gnutls_dtls_ciphers[i].cipher == cipher) { + gnutls_dtls_ciphers[i].disabled = 0; + break; + } + } + } + } + + buf = buf_alloc(); + + for (i = 0; i < sizeof(gnutls_dtls_ciphers)/sizeof(gnutls_dtls_ciphers[0]); i++) { + if (!gnutls_dtls_ciphers[i].disabled) { + if (buf->buf_len == 0) { + buf_append(buf, "%s", gnutls_dtls_ciphers[i].name); + } else { + buf_append(buf, ":%s", gnutls_dtls_ciphers[i].name); + } + } + } + + /* steal buffer */ + p = buf->data; + buf->data = NULL; + + buf_free(buf); + gnutls_priority_deinit(cache); + return p; +} + #define DTLS_SEND gnutls_record_send #define DTLS_RECV gnutls_record_recv #define DTLS_FREE gnutls_deinit @@ -470,7 +537,7 @@ static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd) int cipher; for (cipher = 0; cipher < sizeof(gnutls_dtls_ciphers)/sizeof(gnutls_dtls_ciphers[0]); cipher++) { - if (!strcmp(vpninfo->dtls_cipher, gnutls_dtls_ciphers[cipher].name)) + if (!strcmp(vpninfo->dtls_cipher, gnutls_dtls_ciphers[cipher].name) && !gnutls_dtls_ciphers[cipher].disabled) goto found_cipher; } vpn_progress(vpninfo, PRG_ERR, _("Unknown DTLS parameters for requested CipherSuite '%s'\n"), diff --git a/gnutls.c b/gnutls.c index 34119da..e121842 100644 --- a/gnutls.c +++ b/gnutls.c @@ -2070,7 +2070,6 @@ int openconnect_open_https(struct openconnect_info *vpninfo) { int ssl_sock = -1; int err; - const char * prio; if (vpninfo->https_sess) return 0; @@ -2196,13 +2195,13 @@ int openconnect_open_https(struct openconnect_info *vpninfo) strlen(vpninfo->hostname)); if (vpninfo->pfs) { - prio = DEFAULT_PRIO":-RSA"; + vpninfo->gnutls_default_prio = DEFAULT_PRIO":-RSA"; } else { - prio = DEFAULT_PRIO; + vpninfo->gnutls_default_prio = DEFAULT_PRIO; } err = gnutls_priority_set_direct(vpninfo->https_sess, - prio, NULL); + vpninfo->gnutls_default_prio, NULL); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to set TLS priority string: %s\n"), diff --git a/openconnect-internal.h b/openconnect-internal.h index 04cb226..7b7161c 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -469,6 +469,7 @@ struct openconnect_info { gnutls_session_t https_sess; gnutls_certificate_credentials_t https_cred; char local_cert_md5[MD5_SIZE * 2 + 1]; /* For CSD */ + const char *gnutls_default_prio; #ifdef HAVE_TROUSERS TSS_HCONTEXT tpm_context; TSS_HKEY srk; @@ -765,6 +766,7 @@ int dtls_setup(struct openconnect_info *vpninfo, int dtls_attempt_period); int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout); void dtls_close(struct openconnect_info *vpninfo); void dtls_shutdown(struct openconnect_info *vpninfo); +char *dtls_ciphers_from_conn(struct openconnect_info *vpninfo); /* cstp.c */ void cstp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf); -- 2.1.0