#include <openssl/ssl.h>
#include <openssl/err.h>
+#include <openssl/rand.h>
#include "openconnect.h"
{
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;
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);
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... */
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;
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;
}
return start_cstp_connection(vpninfo);
}
-static int cstp_reconnect(struct openconnect_info *vpninfo)
+int cstp_reconnect(struct openconnect_info *vpninfo)
{
int ret;
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:
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);
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;
}
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);
dtls_opt = dtls_opt->next;
}
- if (!sessid_found || !dtls_port) {
+ if (!dtls_port) {
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
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;
}
#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
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
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);
<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>
<hr>
<address>David Woodhouse <<A HREF="mailto:dwmw2@infradead.org">dwmw2@infradead.org</A>></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>