diff --git a/gnutls.c b/gnutls.c index 4bc863d2..b12ee5d8 100644 --- a/gnutls.c +++ b/gnutls.c @@ -1784,11 +1784,14 @@ static int verify_peer(gnutls_session_t session) return err; } +#define DEFAULT_PRIO "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.0:" \ + "%COMPAT:%DISABLE_SAFE_RENEGOTIATION:%LATEST_RECORD_VERSION" int openconnect_open_https(struct openconnect_info *vpninfo) { int ssl_sock = -1; int err; + const char * prio; if (vpninfo->https_sess) return 0; @@ -1895,13 +1898,18 @@ int openconnect_open_https(struct openconnect_info *vpninfo) gnutls_sign_callback_set(vpninfo->https_sess, gtls2_tpm_sign_cb, vpninfo); #endif - err = gnutls_priority_set_direct(vpninfo->https_sess, - "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.0:" + if (vpninfo->pfs) { + prio = DEFAULT_PRIO":-RSA"; + } else { + prio = DEFAULT_PRIO #if GNUTLS_VERSION_MAJOR >= 3 - "-CURVE-ALL:" + ":-CURVE-ALL" #endif - "%COMPAT:%DISABLE_SAFE_RENEGOTIATION:%LATEST_RECORD_VERSION", - NULL); + ; + } + + err = gnutls_priority_set_direct(vpninfo->https_sess, + prio, NULL); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to set TLS priority string: %s\n"), diff --git a/main.c b/main.c index c66f77a0..1c9e5f65 100644 --- a/main.c +++ b/main.c @@ -125,6 +125,7 @@ enum { OPT_TOKEN_SECRET, OPT_OS, OPT_TIMESTAMP, + OPT_PFS, }; #ifdef __sun__ @@ -139,6 +140,7 @@ enum { static struct option long_options[] = { OPTION("background", 0, 'b'), + OPTION("pfs", 0, OPT_PFS), OPTION("pid-file", 1, OPT_PIDFILE), OPTION("certificate", 1, 'c'), OPTION("sslkey", 1, 'k'), @@ -281,6 +283,7 @@ static void usage(void) #ifndef LIBPROXY_HDR printf(" %s\n", _("(NOTE: libproxy disabled in this build)")); #endif + printf(" --pfs %s\n", _("Require perfect forward secrecy")); printf(" -q, --quiet %s\n", _("Less output")); printf(" -Q, --queue-len=LEN %s\n", _("Set packet queue limit to LEN pkts")); printf(" -s, --script=SCRIPT %s\n", _("Shell command line for using a vpnc-compatible config script")); @@ -580,6 +583,9 @@ int main(int argc, char **argv) case OPT_PIDFILE: pidfile = keep_config_arg(); break; + case OPT_PFS: + vpninfo->pfs = 1; + break; case OPT_SERVERCERT: openconnect_set_server_cert_sha1(vpninfo, xstrdup(config_arg)); break; diff --git a/openconnect-internal.h b/openconnect-internal.h index 7dd6d285..632c2db6 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -196,6 +196,7 @@ struct openconnect_info { struct oc_vpn_option *cstp_options; struct oc_vpn_option *dtls_options; + unsigned pfs; #if defined(OPENCONNECT_OPENSSL) X509 *cert_x509; SSL_CTX *https_ctx; diff --git a/openconnect.8.in b/openconnect.8.in index 1f69c61c..733cb381 100644 --- a/openconnect.8.in +++ b/openconnect.8.in @@ -46,6 +46,7 @@ openconnect \- Connect to Cisco AnyConnect VPN .OP \-\-dtls\-local\-port port .OP \-\-dump\-http\-traffic .OP \-\-no\-cert\-check +.OP \-\-pfs .OP \-\-no\-dtls .OP \-\-no\-http\-keepalive .OP \-\-no\-passwd @@ -308,6 +309,13 @@ still add them (or your private CA) to a local file and use that file with the .B \-\-cafile option. +.TP +.B \-\-pfs +Enforces Perfect Forward Secrecy (PFS). That ensures that if the server's +long-term key is compromised, any session keys established before the compromise +will be unaffected. If this option is provided and the server does not support PFS +in the TLS channel the connection will fail. + .TP .B \-\-no\-dtls Disable DTLS diff --git a/openssl.c b/openssl.c index a8754660..f8a6eb1f 100644 --- a/openssl.c +++ b/openssl.c @@ -1304,6 +1304,9 @@ int openconnect_open_https(struct openconnect_info *vpninfo) ssl_app_verify_callback, NULL); #endif SSL_CTX_set_default_verify_paths(vpninfo->https_ctx); + + if (vpninfo->pfs) + SSL_CTX_set_cipher_list(vpninfo->https_ctx, "HIGH:!aNULL:!eNULL:-RSA"); #ifdef ANDROID_KEYSTORE if (vpninfo->cafile && !strncmp(vpninfo->cafile, "keystore:", 9)) {