Skip to content

Commit

Permalink
Implement DTLS and CSTP rekeying.
Browse files Browse the repository at this point in the history
Don't know if there's a way to pass a new DTLS master secret and get
back a new session-id over an existing CSTP connection; reconnecting the
CSTP works though. And is the way to rekey CSTP too, since SSL
renegotiation got deprecated (we never got round to doing it that way
either, anyway).

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Aug 11, 2010
1 parent 08cfd39 commit 9d2b41d
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 38 deletions.
40 changes: 34 additions & 6 deletions cstp.c
Expand Up @@ -32,6 +32,7 @@

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>

#include "openconnect.h"

Expand Down Expand Up @@ -68,7 +69,7 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
{
char buf[65536];
int i;
int retried = 0;
int retried = 0, sessid_found = 0;
struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
Expand Down Expand Up @@ -100,6 +101,15 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
inc = next;
}
vpninfo->split_includes = vpninfo->split_excludes = NULL;

/* Create (new) random master key for DTLS connection, if needed */
if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
time(NULL) + 300 &&
RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
fprintf(stderr, "Failed to initialise DTLS secret\n");
exit(1);
}

retry:
openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
Expand Down Expand Up @@ -197,6 +207,19 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
if (!strncmp(buf, "X-DTLS-", 7)) {
*next_dtls_option = new_option;
next_dtls_option = &new_option->next;

if (!strcmp(buf + 7, "Session-ID")) {
if (strlen(colon) != 64) {
vpninfo->progress(vpninfo, PRG_ERR, "X-DTLS-Session-ID not 64 characters\n");
vpninfo->progress(vpninfo, PRG_ERR, "Is: %s\n", colon);
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
for (i = 0; i < 64; i += 2)
vpninfo->dtls_session_id[i/2] = unhex(colon + i);
sessid_found = 1;
time(&vpninfo->dtls_times.last_rekey);
}
continue;
}
/* CSTP options... */
Expand All @@ -210,6 +233,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
int j = atol(colon);
if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
vpninfo->ssl_times.dpd = j;
} else if (!strcmp(buf + 7, "Rekey-Time")) {
vpninfo->ssl_times.rekey = atol(colon);
} else if (!strcmp(buf + 7, "Content-Encoding")) {
if (!strcmp(colon, "deflate"))
vpninfo->deflate = 1;
Expand Down Expand Up @@ -330,7 +355,11 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);

vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
if (!sessid_found)
vpninfo->dtls_attempt_period = 0;

vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
vpninfo->ssl_times.last_tx = time(NULL);
return 0;
}

Expand Down Expand Up @@ -368,7 +397,7 @@ int make_cstp_connection(struct openconnect_info *vpninfo)
return start_cstp_connection(vpninfo);
}

static int cstp_reconnect(struct openconnect_info *vpninfo)
int cstp_reconnect(struct openconnect_info *vpninfo)
{
int ret;
int timeout;
Expand Down Expand Up @@ -589,9 +618,8 @@ int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
case KA_REKEY:
/* Not that this will ever happen; we don't even process
the setting when we're asked for it. */
vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
time(&vpninfo->ssl_times.last_rekey);
work_done = 1;
vpninfo->progress(vpninfo, PRG_INFO, "CSTP rekey due\n");
goto do_reconnect;
break;

case KA_DPD_DEAD:
Expand Down
48 changes: 22 additions & 26 deletions dtls.c
Expand Up @@ -177,15 +177,16 @@ int connect_dtls_socket(struct openconnect_info *vpninfo)
return -EINVAL;
}
vpninfo->dtls_session->ssl_version = 0x0100; // DTLS1_BAD_VER
}

vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
sizeof(vpninfo->dtls_secret));
/* Do this every time; it may have changed due to a rekey */
vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
sizeof(vpninfo->dtls_secret));

vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
sizeof(vpninfo->dtls_session_id));
}
vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
sizeof(vpninfo->dtls_session_id));

dtls_ssl = SSL_new(vpninfo->dtls_ctx);
SSL_set_connect_state(dtls_ssl);
Expand Down Expand Up @@ -269,8 +270,7 @@ int dtls_try_handshake(struct openconnect_info *vpninfo)
vpninfo->new_dtls_ssl = NULL;
vpninfo->new_dtls_fd = -1;

vpninfo->dtls_times.last_rekey = vpninfo->dtls_times.last_rx =
vpninfo->dtls_times.last_tx = time(NULL);
vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);

return 0;
}
Expand Down Expand Up @@ -329,26 +329,14 @@ static int dtls_restart(struct openconnect_info *vpninfo)
int setup_dtls(struct openconnect_info *vpninfo)
{
struct vpn_option *dtls_opt = vpninfo->dtls_options;
int sessid_found = 0;
int dtls_port = 0;
int i;

while (dtls_opt) {
vpninfo->progress(vpninfo, PRG_TRACE,
"DTLS option %s : %s\n",
dtls_opt->option, dtls_opt->value);

if (!strcmp(dtls_opt->option, "X-DTLS-Session-ID")) {
if (strlen(dtls_opt->value) != 64) {
vpninfo->progress(vpninfo, PRG_ERR, "X-DTLS-Session-ID not 64 characters\n");
vpninfo->progress(vpninfo, PRG_ERR, "Is: %s\n", dtls_opt->value);
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
for (i = 0; i < 64; i += 2)
vpninfo->dtls_session_id[i/2] = unhex(dtls_opt->value + i);
sessid_found = 1;
} else if (!strcmp(dtls_opt->option + 7, "Port")) {
if (!strcmp(dtls_opt->option + 7, "Port")) {
dtls_port = atol(dtls_opt->value);
} else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
Expand All @@ -364,7 +352,7 @@ int setup_dtls(struct openconnect_info *vpninfo)

dtls_opt = dtls_opt->next;
}
if (!sessid_found || !dtls_port) {
if (!dtls_port) {
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
Expand Down Expand Up @@ -457,9 +445,17 @@ int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)

switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
case KA_REKEY:
time(&vpninfo->dtls_times.last_rekey);
vpninfo->progress(vpninfo, PRG_TRACE, "DTLS rekey due\n");
if (connect_dtls_socket(vpninfo)) {
vpninfo->progress(vpninfo, PRG_INFO, "DTLS rekey due\n");

/* There ought to be a method of rekeying DTLS without tearing down
the CSTP session and restarting, but we don't (yet) know it */
if (cstp_reconnect(vpninfo)) {
vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
vpninfo->quit_reason = "CSTP reconnect failed";
return 1;
}

if (dtls_restart(vpninfo)) {
vpninfo->progress(vpninfo, PRG_ERR, "DTLS rekey failed\n");
return 1;
}
Expand Down
5 changes: 0 additions & 5 deletions main.c
Expand Up @@ -36,7 +36,6 @@
#include <sys/syslog.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <openssl/rand.h>
#include <openssl/ui.h>
#ifdef OPENCONNECT_LIBPROXY
#include LIBPROXY_HDR
Expand Down Expand Up @@ -240,10 +239,6 @@ int main(int argc, char **argv)
vpninfo->uid_csd_given = 0;
vpninfo->validate_peer_cert = validate_peer_cert;

if (RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
fprintf(stderr, "Failed to initialise DTLS secret\n");
exit(1);
}
if (!uname(&utsbuf))
vpninfo->localname = utsbuf.nodename;
else
Expand Down
1 change: 1 addition & 0 deletions openconnect.h
Expand Up @@ -299,6 +299,7 @@ int connect_dtls_socket(struct openconnect_info *vpninfo);
int make_cstp_connection(struct openconnect_info *vpninfo);
int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout);
int cstp_bye(struct openconnect_info *vpninfo, char *reason);
int cstp_reconnect(struct openconnect_info *vpninfo);

/* ssl.c */
void openconnect_init_openssl(void);
Expand Down
3 changes: 2 additions & 1 deletion openconnect.html
Expand Up @@ -181,6 +181,7 @@ <H2>Release Notes / Changelog</H2>
<UL>
<LI><B>OpenConnect HEAD</B><BR>
<UL>
<LI>Implement CSTP and DTLS rekeying <I>(both by reconnecting CSTP)</I>.</LI>
<LI>Add <TT>--force-dpd</TT> option to set minimum DPD interval.</LI>
<LI>Don't print <TT>webvpn</TT> cookie in debug output.</LI>
</UL><BR>
Expand Down Expand Up @@ -436,6 +437,6 @@ <H3>FreeBSD</H3>
<hr>
<address>David Woodhouse &lt;<A HREF="mailto:dwmw2@infradead.org">dwmw2@infradead.org</A>&gt;</address>
<!-- hhmts start -->
Last modified: Sat Aug 7 18:50:17 BST 2010
Last modified: Thu Aug 12 00:13:52 BST 2010
<!-- hhmts end -->
</body> </html>

0 comments on commit 9d2b41d

Please sign in to comment.