mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
Merge branch 'tmp-dtls12' into 'master'
Added support for DTLS1.2 with anyconnect clients Closes #193 and #188 See merge request openconnect/ocserv!92
This commit is contained in:
1
NEWS
1
NEWS
@@ -1,6 +1,7 @@
|
||||
* Version 0.12.2 (unreleased)
|
||||
- Added support for AES256-SHA legacy cipher. This allows the anyconnect
|
||||
clients to use AES256.
|
||||
- Added support for the DTLS1.2 protocol hack used by in Anyconnect clients.
|
||||
|
||||
|
||||
* Version 0.12.1 (released 2018-05-12)
|
||||
|
||||
@@ -12,6 +12,7 @@ X-DTLS-Accept-Encoding, HEADER_DTLS_ENCODING
|
||||
Connection, HEADER_CONNECTION
|
||||
X-DTLS-Master-Secret, HEADER_MASTER_SECRET
|
||||
X-DTLS-CipherSuite, HEADER_DTLS_CIPHERSUITE
|
||||
X-DTLS12-CipherSuite, HEADER_DTLS12_CIPHERSUITE
|
||||
X-CSTP-Base-MTU, HEADER_CSTP_BASE_MTU
|
||||
X-CSTP-MTU, HEADER_CSTP_MTU
|
||||
X-CSTP-Address-Type, HEADER_CSTP_ATYPE
|
||||
|
||||
@@ -90,7 +90,6 @@ static const dtls_ciphersuite_st ciphersuites[] = {
|
||||
.gnutls_mac = GNUTLS_MAC_AEAD,
|
||||
.gnutls_kx = GNUTLS_KX_RSA,
|
||||
.gnutls_cipher = GNUTLS_CIPHER_AES_128_GCM,
|
||||
.txt_version = "3.2.7",
|
||||
.server_prio = 80},
|
||||
{
|
||||
.oc_name = CS_AES256_GCM,
|
||||
@@ -101,7 +100,6 @@ static const dtls_ciphersuite_st ciphersuites[] = {
|
||||
.gnutls_kx = GNUTLS_KX_RSA,
|
||||
.gnutls_cipher = GNUTLS_CIPHER_AES_256_GCM,
|
||||
.server_prio = 90,
|
||||
.txt_version = "3.2.7",
|
||||
},
|
||||
{
|
||||
.oc_name = "AES256-SHA",
|
||||
@@ -135,6 +133,39 @@ static const dtls_ciphersuite_st ciphersuites[] = {
|
||||
}
|
||||
};
|
||||
|
||||
/* In the following we use %NO_SESSION_HASH:%DISABLE_SAFE_RENEGOTIATION because certain
|
||||
* versions of openssl send the extended master secret extension in this
|
||||
* resumed session. Since the state of this extension is undefined
|
||||
* (it's not a real session we are resuming), we explicitly disable this
|
||||
* extension to avoid interop issues. Furthermore gnutls does seem to
|
||||
* be sending the renegotiation extension which openssl doesn't like (see #193) */
|
||||
|
||||
#define WORKAROUND_STR "%NO_SESSION_HASH:%DISABLE_SAFE_RENEGOTIATION"
|
||||
static const dtls_ciphersuite_st ciphersuites12[] = {
|
||||
{
|
||||
.oc_name = "AES128-GCM-SHA256",
|
||||
.gnutls_name =
|
||||
"NONE:+VERS-DTLS1.2:+COMP-NULL:+AES-128-GCM:+AEAD:+RSA:+SIGN-ALL:"WORKAROUND_STR,
|
||||
.gnutls_version = GNUTLS_DTLS1_2,
|
||||
.gnutls_mac = GNUTLS_MAC_AEAD,
|
||||
.gnutls_kx = GNUTLS_KX_RSA,
|
||||
.gnutls_cipher = GNUTLS_CIPHER_AES_128_GCM,
|
||||
.dtls12_mode = 1,
|
||||
.server_prio = 50
|
||||
},
|
||||
{
|
||||
.oc_name = "AES256-GCM-SHA384",
|
||||
.gnutls_name =
|
||||
"NONE:+VERS-DTLS1.2:+COMP-NULL:+AES-256-GCM:+AEAD:+RSA:+SIGN-ALL:"WORKAROUND_STR,
|
||||
.gnutls_version = GNUTLS_DTLS1_2,
|
||||
.gnutls_mac = GNUTLS_MAC_AEAD,
|
||||
.gnutls_kx = GNUTLS_KX_RSA,
|
||||
.gnutls_cipher = GNUTLS_CIPHER_AES_256_GCM,
|
||||
.dtls12_mode = 1,
|
||||
.server_prio = 90
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef HAVE_LZ4
|
||||
/* Wrappers over LZ4 functions */
|
||||
static
|
||||
@@ -223,6 +254,7 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req)
|
||||
char *token, *value;
|
||||
char *str, *p;
|
||||
const dtls_ciphersuite_st *cand = NULL;
|
||||
const dtls_ciphersuite_st *saved_ciphersuite;
|
||||
const compression_method_st *comp_cand = NULL;
|
||||
const compression_method_st **selected_comp;
|
||||
int want_cipher;
|
||||
@@ -344,7 +376,9 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req)
|
||||
break;
|
||||
|
||||
case HEADER_DTLS_CIPHERSUITE:
|
||||
req->selected_ciphersuite = NULL;
|
||||
if (req->use_psk || !WSCONFIG(ws)->dtls_legacy)
|
||||
break;
|
||||
|
||||
str = (char *)value;
|
||||
|
||||
p = strstr(str, DTLS_PROTO_INDICATOR);
|
||||
@@ -353,10 +387,14 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req)
|
||||
if (WSCONFIG(ws)->dtls_psk) {
|
||||
req->use_psk = 1;
|
||||
req->master_secret_set = 1; /* we don't need it */
|
||||
req->selected_ciphersuite = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (req->selected_ciphersuite) /* if set via HEADER_DTLS12_CIPHERSUITE */
|
||||
break;
|
||||
|
||||
if (ws->session != NULL) {
|
||||
want_mac = gnutls_mac_get(ws->session);
|
||||
want_cipher = gnutls_cipher_get(ws->session);
|
||||
@@ -370,10 +408,6 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req)
|
||||
i < sizeof(ciphersuites) / sizeof(ciphersuites[0]);
|
||||
i++) {
|
||||
if (strcmp(token, ciphersuites[i].oc_name) == 0) {
|
||||
if (ciphersuites[i].txt_version != NULL && gnutls_check_version(ciphersuites[i].txt_version) == NULL) {
|
||||
continue; /* not supported */
|
||||
}
|
||||
|
||||
if (cand == NULL ||
|
||||
cand->server_prio < ciphersuites[i].server_prio ||
|
||||
(want_cipher != -1 && want_cipher == ciphersuites[i].gnutls_cipher &&
|
||||
@@ -397,6 +431,76 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req)
|
||||
req->selected_ciphersuite = cand;
|
||||
|
||||
break;
|
||||
|
||||
case HEADER_DTLS12_CIPHERSUITE:
|
||||
if (req->use_psk || !WSCONFIG(ws)->dtls_legacy)
|
||||
break;
|
||||
|
||||
/* in gnutls 3.6.0+ there is a regression which makes
|
||||
* anyconnect's openssl fail: https://gitlab.com/gnutls/gnutls/merge_requests/868
|
||||
*/
|
||||
#ifdef gnutls_check_version_numeric
|
||||
if (!gnutls_check_version_numeric(3,6,6) &&
|
||||
(!gnutls_check_version_numeric(3,3,0) || gnutls_check_version_numeric(3,6,0))) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
str = (char *)value;
|
||||
|
||||
p = strstr(str, DTLS_PROTO_INDICATOR);
|
||||
if (p != NULL && (p[sizeof(DTLS_PROTO_INDICATOR)-1] == 0 || p[sizeof(DTLS_PROTO_INDICATOR)-1] == ':')) {
|
||||
/* OpenConnect DTLS setup was detected. */
|
||||
if (WSCONFIG(ws)->dtls_psk) {
|
||||
req->use_psk = 1;
|
||||
req->master_secret_set = 1; /* we don't need it */
|
||||
req->selected_ciphersuite = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
saved_ciphersuite = req->selected_ciphersuite;
|
||||
req->selected_ciphersuite = NULL;
|
||||
|
||||
if (ws->session != NULL) {
|
||||
want_mac = gnutls_mac_get(ws->session);
|
||||
want_cipher = gnutls_cipher_get(ws->session);
|
||||
} else {
|
||||
want_mac = -1;
|
||||
want_cipher = -1;
|
||||
}
|
||||
|
||||
while ((token = strtok(str, ":")) != NULL) {
|
||||
for (i = 0;
|
||||
i < sizeof(ciphersuites12) / sizeof(ciphersuites12[0]);
|
||||
i++) {
|
||||
if (strcmp(token, ciphersuites12[i].oc_name) == 0) {
|
||||
if (cand == NULL ||
|
||||
cand->server_prio < ciphersuites12[i].server_prio ||
|
||||
(want_cipher != -1 && want_cipher == ciphersuites12[i].gnutls_cipher &&
|
||||
want_mac == ciphersuites12[i].gnutls_mac)) {
|
||||
cand =
|
||||
&ciphersuites12[i];
|
||||
|
||||
/* if our candidate matches the TLS session
|
||||
* ciphersuite, we are finished */
|
||||
if (want_cipher != -1) {
|
||||
if (want_cipher == cand->gnutls_cipher &&
|
||||
want_mac == cand->gnutls_mac)
|
||||
goto ciphersuite12_finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
str = NULL;
|
||||
}
|
||||
ciphersuite12_finish:
|
||||
req->selected_ciphersuite = cand;
|
||||
|
||||
if (req->selected_ciphersuite == NULL && saved_ciphersuite)
|
||||
req->selected_ciphersuite = saved_ciphersuite;
|
||||
|
||||
break;
|
||||
#ifdef ENABLE_COMPRESSION
|
||||
case HEADER_DTLS_ENCODING:
|
||||
case HEADER_CSTP_ENCODING:
|
||||
|
||||
@@ -274,7 +274,7 @@ static int setup_dtls_psk_keys(gnutls_session_t session, struct worker_st *ws)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_dtls0_9_keys(gnutls_session_t session, struct worker_st *ws)
|
||||
static int setup_legacy_dtls_keys(gnutls_session_t session, struct worker_st *ws)
|
||||
{
|
||||
int ret;
|
||||
gnutls_datum_t master =
|
||||
@@ -351,8 +351,8 @@ static int setup_dtls_connection(struct worker_st *ws)
|
||||
oclog(ws, LOG_INFO, "CISCO client compatibility (dtls-legacy) is disabled; will not setup a DTLS session");
|
||||
goto fail;
|
||||
}
|
||||
oclog(ws, LOG_INFO, "setting up DTLS-0.9 connection");
|
||||
ret = setup_dtls0_9_keys(session, ws);
|
||||
oclog(ws, LOG_INFO, "setting up legacy DTLS (resumption) connection");
|
||||
ret = setup_legacy_dtls_keys(session, ws);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -2208,8 +2208,9 @@ static int connect_handler(worker_st * ws)
|
||||
oclog(ws, LOG_INFO, "DTLS ciphersuite: %s",
|
||||
ws->req.selected_ciphersuite->oc_name);
|
||||
ret =
|
||||
cstp_printf(ws, "X-DTLS-CipherSuite: %s\r\n",
|
||||
ws->req.selected_ciphersuite->oc_name);
|
||||
cstp_printf(ws, "X-DTLS%s-CipherSuite: %s\r\n",
|
||||
(ws->req.selected_ciphersuite->dtls12_mode!=0)?"12":"",
|
||||
ws->req.selected_ciphersuite->oc_name);
|
||||
SEND_ERR(ret);
|
||||
|
||||
/* only send the X-DTLS-MTU in the legacy protocol, as there
|
||||
|
||||
@@ -57,6 +57,7 @@ enum {
|
||||
HEADER_DEVICE_TYPE,
|
||||
HEADER_PLATFORM,
|
||||
HEADER_DTLS_CIPHERSUITE,
|
||||
HEADER_DTLS12_CIPHERSUITE,
|
||||
HEADER_CONNECTION,
|
||||
HEADER_FULL_IPV6,
|
||||
HEADER_USER_AGENT,
|
||||
@@ -100,12 +101,12 @@ typedef struct compression_method_st {
|
||||
typedef struct dtls_ciphersuite_st {
|
||||
const char* oc_name;
|
||||
const char* gnutls_name; /* the gnutls priority string to set */
|
||||
unsigned dtls12_mode;
|
||||
unsigned server_prio; /* the highest the more we want to negotiate that */
|
||||
unsigned gnutls_cipher;
|
||||
unsigned gnutls_kx;
|
||||
unsigned gnutls_mac;
|
||||
unsigned gnutls_version;
|
||||
const char *txt_version;
|
||||
} dtls_ciphersuite_st;
|
||||
|
||||
#ifdef HAVE_GSSAPI
|
||||
|
||||
Reference in New Issue
Block a user