From 555d2cb03e4dad17dae0c35ccae855ef8965c99e Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 13 Sep 2016 13:25:35 +0200 Subject: [PATCH] Added the match-tls-and-dtls-ciphers config option That when enable, it will prevent any DTLS negotiation other than the DTLS-PSK, and will ensure that the cipher/mac combination matches on the TLS and DTLS connections. The cisco-client-compat config option when disabled, it will disable the pre-draft-DTLS negotiation. --- doc/sample.config | 17 ++++++++++++----- src/config.c | 10 ++++++++++ src/ocserv-args.def | 17 ++++++++++++----- src/vpn.h | 4 ++++ src/worker-http.c | 2 +- src/worker-vpn.c | 14 ++++++++++++-- 6 files changed, 51 insertions(+), 13 deletions(-) diff --git a/doc/sample.config b/doc/sample.config index 9af05f73..0999097f 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -263,6 +263,14 @@ tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-SSL3.0" # on the main channel. #tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128" +# That option requires the established DTLS channel to use the same +# cipher as the primary TLS channel. This cannot be combined with +# listen-clear-file since the ciphersuite information is not available +# in that configuration. Note also, that this option implies that +# cisco-client-compat is false; this protection cannot be enforced +# in the legacy/compat protocol. +#match-tls-and-dtls-ciphers = true + # The time (in seconds) that a client is allowed to stay connected prior # to authentication auth-timeout = 240 @@ -574,11 +582,10 @@ no-route = 192.168.5.0/255.255.255.0 # The following options are for (experimental) AnyConnect client # compatibility. -# This option must be set to true to support legacy CISCO clients. -# A side effect of this option is that it will no longer be required -# for clients to present their certificate on every connection. -# That is they may resume a cookie without presenting a certificate -# (when certificate authentication is used). +# This option will enable the pre-draft-DTLS version of DTLS, and +# will not require clients to present their certificate on every TLS +# connection. It must be set to true to support legacy CISCO clients +# and openconnect clients < 7.08. cisco-client-compat = true # Client profile xml. A sample file exists in doc/profile.xml. diff --git a/src/config.c b/src/config.c index 0ae16d10..45c43a40 100644 --- a/src/config.c +++ b/src/config.c @@ -185,6 +185,7 @@ static struct cfg_options available_options[] = { { .name = "config-per-group", .type = OPTION_STRING, .mandatory = 0 }, { .name = "default-user-config", .type = OPTION_STRING, .mandatory = 0 }, { .name = "default-group-config", .type = OPTION_STRING, .mandatory = 0 }, + { .name = "match-tls-and-dtls-ciphers", .type = OPTION_BOOLEAN, .mandatory = 0 }, }; static const tOptionValue* get_option(const char* name, unsigned * mand) @@ -815,6 +816,7 @@ size_t urlfw_size = 0; } READ_STRING("banner", config->banner); + READ_TF("cisco-client-compat", config->cisco_client_compat, 0); READ_TF("always-require-cert", force_cert_auth, 1); if (force_cert_auth == 0) { @@ -822,6 +824,14 @@ size_t urlfw_size = 0; config->cisco_client_compat = 1; } + READ_TF("match-tls-and-dtls-ciphers", config->match_dtls_and_tls, 0); + if (config->match_dtls_and_tls) { + if (config->cisco_client_compat) { + fprintf(stderr, "note that 'match-tls-and-dtls-ciphers' cannot be applied when 'cisco-client-compat' is on; disabling\n"); + } + config->cisco_client_compat = 0; + } + READ_TF("compression", config->enable_compression, 0); READ_NUMERIC("no-compress-limit", config->no_compress_limit); if (config->no_compress_limit == 0) diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 9e50cf84..72180a9b 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -361,6 +361,14 @@ tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-SSL3.0" # on the main channel. #tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128" +# That option requires the established DTLS channel to use the same +# cipher as the primary TLS channel. This cannot be combined with +# listen-clear-file since the ciphersuite information is not available +# in that configuration. Note also, that this option implies that +# cisco-client-compat is false; this protection cannot be enforced +# in the legacy/compat protocol. +#match-tls-and-dtls-ciphers = true + # The time (in seconds) that a client is allowed to stay connected prior # to authentication auth-timeout = 240 @@ -696,11 +704,10 @@ no-route = 192.168.5.0/255.255.255.0 # The following options are for (experimental) AnyConnect client # compatibility. -# This option must be set to true to support legacy CISCO clients. -# A side effect of this option is that it will no longer be required -# for clients to present their certificate on every connection. -# That is they may resume a cookie without presenting a certificate -# (when certificate authentication is used). +# This option will enable the pre-draft-DTLS version of DTLS, and +# will not require clients to present their certificate on every TLS +# connection. It must be set to true to support legacy CISCO clients +# and openconnect clients < 7.08. cisco-client-compat = true # Client profile xml. A sample file exists in doc/profile.xml. diff --git a/src/vpn.h b/src/vpn.h index 5949f1f7..976899b3 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -346,6 +346,10 @@ struct cfg_st { unsigned ban_points_connect; unsigned ban_points_kkdcp; + /* when using the new PSK DTLS negotiation make sure that + * the negotiated DTLS cipher/mac matches the TLS cipher/mac. */ + unsigned match_dtls_and_tls; + unsigned isolate; /* whether seccomp should be enabled or not */ unsigned auth_timeout; /* timeout of HTTP auth */ diff --git a/src/worker-http.c b/src/worker-http.c index 3a6871c2..2fdc1144 100644 --- a/src/worker-http.c +++ b/src/worker-http.c @@ -199,7 +199,7 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req) switch (req->next_header) { case HEADER_MASTER_SECRET: - if (req->use_psk) /* ignored */ + if (req->use_psk || !ws->config->cisco_client_compat) /* ignored */ break; if (value_length < TLS_MASTER_SIZE * 2) { diff --git a/src/worker-vpn.c b/src/worker-vpn.c index c6093c1c..513f6672 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -211,13 +211,18 @@ static int setup_dtls_psk_keys(gnutls_session_t session, struct worker_st *ws) gnutls_mac_algorithm_t mac; gnutls_cipher_algorithm_t cipher; - if (ws->session) { + if (ws->session && ws->config->match_dtls_and_tls) { cipher = gnutls_cipher_get(ws->session); mac = gnutls_mac_get(ws->session); snprintf(prio_string, sizeof(prio_string), "%s:-VERS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+PSK:+VERS-DTLS-ALL:+%s:+%s", ws->config->priorities, gnutls_mac_get_name(mac), gnutls_cipher_get_name(cipher)); } else { + if (ws->config->match_dtls_and_tls) { + oclog(ws, LOG_ERR, "cannot determine ciphersuite from CSTP channel (unset match-tls-and-dtls-ciphers)"); + return -1; + } + /* if we haven't an associated session, enable all ciphers we would have enabled * otherwise for TLS. */ snprintf(prio_string, sizeof(prio_string), "%s:-VERS-ALL:-KX-ALL:+PSK:+VERS-DTLS-ALL", @@ -327,6 +332,11 @@ static int setup_dtls_connection(struct worker_st *ws) oclog(ws, LOG_INFO, "setting up DTLS-PSK connection"); ret = setup_dtls_psk_keys(session, ws); } else { + if (!ws->config->cisco_client_compat) { + oclog(ws, LOG_INFO, "CISCO client compatibility is disabled; will not setup a legacy DTLS session"); + ret = -1; + goto fail; + } oclog(ws, LOG_INFO, "setting up DTLS-0.9 connection"); ret = setup_dtls0_9_keys(session, ws); } @@ -1958,7 +1968,7 @@ static int connect_handler(worker_st * ws) ws->user_config->keepalive); SEND_ERR(ret); - if (ws->req.use_psk) { + if (ws->req.use_psk || !ws->config->cisco_client_compat) { oclog(ws, LOG_INFO, "DTLS ciphersuite: PSK"); ret = cstp_printf(ws, "X-DTLS-CipherSuite: PSK\r\n");