aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/openvpn/forward.c4
-rw-r--r--src/openvpn/multi.c81
-rw-r--r--src/openvpn/openvpn.h2
-rw-r--r--src/openvpn/push.c66
4 files changed, 88 insertions, 65 deletions
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 885cf12..5c4370a 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -1123,8 +1123,8 @@ process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, boo
}
/*
- * Drop non-TLS packet if client-connect script/plugin has not
- * yet succeeded.
+ * Drop non-TLS packet if client-connect script/plugin and cipher selection
+ * has not yet succeeded.
*/
if (c->c2.context_auth != CAS_SUCCEEDED)
{
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 818700c..5db32cc 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -824,8 +824,8 @@ multi_create_instance(struct multi_context *m, const struct mroute_addr *real)
mi->did_cid_hash = true;
#endif
-#ifdef ENABLE_ASYNC_PUSH
mi->context.c2.push_request_received = false;
+#ifdef ENABLE_ASYNC_PUSH
mi->inotify_watch = -1;
#endif
@@ -1772,6 +1772,78 @@ multi_client_connect_setenv(struct multi_context *m,
gc_free(&gc);
}
+/**
+ * Calculates the options that depend on the client capabilities
+ * based on local options and available peer info
+ * - choosen cipher
+ * - peer id
+ */
+static void
+multi_client_set_protocol_options(struct context *c)
+{
+
+ const char *optstr = NULL;
+ struct tls_multi *tls_multi = c->c2.tls_multi;
+ const char *const peer_info = tls_multi->peer_info;
+ struct options *o = &c->options;
+
+ /* Send peer-id if client supports it */
+ optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL;
+ if (optstr)
+ {
+ int proto = 0;
+ int r = sscanf(optstr, "IV_PROTO=%d", &proto);
+ if ((r == 1) && (proto >= 2))
+ {
+ tls_multi->use_peer_id = true;
+ }
+ }
+
+ /* Select cipher if client supports Negotiable Crypto Parameters */
+ if (o->ncp_enabled)
+ {
+ /* if we have already created our key, we cannot *change* our own
+ * cipher -> so log the fact and push the "what we have now" cipher
+ * (so the client is always told what we expect it to use)
+ */
+ const struct tls_session *session = &tls_multi->session[TM_ACTIVE];
+ if (session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized)
+ {
+ msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but "
+ "server has already generated data channel keys, "
+ "re-sending previously negotiated cipher '%s'",
+ o->ciphername );
+ }
+ else
+ {
+ /*
+ * Push the first cipher from --ncp-ciphers to the client that
+ * the client announces to be supporting.
+ */
+ char *push_cipher = ncp_get_best_cipher(o->ncp_ciphers, o->ciphername,
+ peer_info,
+ tls_multi->remote_ciphername,
+ &o->gc);
+
+ if (push_cipher)
+ {
+ o->ciphername = push_cipher;
+ }
+ else
+ {
+ struct gc_arena gc = gc_new();
+ const char *peer_ciphers = tls_peer_ncp_list(peer_info, &gc);
+ msg(M_INFO, "PUSH: No common cipher between server and client."
+ "Expect this connection not to work. "
+ "Server ncp-ciphers: '%s', client supported ciphers '%s'",
+ o->ncp_ciphers, peer_ciphers);
+ gc_free(&gc);
+ }
+ }
+ }
+}
+
+
/*
* Called as soon as the SSL/TLS connection authenticates.
*
@@ -2074,13 +2146,14 @@ script_failed:
/* set context-level authentication flag */
mi->context.c2.context_auth = CAS_SUCCEEDED;
-#ifdef ENABLE_ASYNC_PUSH
- /* authentication complete, send push reply */
+ /* authentication complete, calculate dynamic client specific options */
+ multi_client_set_protocol_options(&mi->context);
+
+ /* send push reply if ready*/
if (mi->context.c2.push_request_received)
{
process_incoming_push_request(&mi->context);
}
-#endif
}
else
{
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index 4609af3..a130885 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -432,9 +432,7 @@ struct context_2
#if P2MP
/* --ifconfig endpoints to be pushed to client */
-#ifdef ENABLE_ASYNC_PUSH
bool push_request_received;
-#endif
bool push_ifconfig_defined;
time_t sent_push_reply_expiry;
in_addr_t push_ifconfig_local;
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 7fec2a3..8d3aa39 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -437,7 +437,7 @@ prepare_auth_token_push_reply(struct tls_multi *tls_multi, struct gc_arena *gc,
}
/**
- * Prepare push options, based on local options and available peer info.
+ * Prepare push options, based on local options
*
* @param context context structure storing data for VPN tunnel
* @param gc gc arena for allocating push options
@@ -449,9 +449,7 @@ bool
prepare_push_reply(struct context *c, struct gc_arena *gc,
struct push_list *push_list)
{
- const char *optstr = NULL;
struct tls_multi *tls_multi = c->c2.tls_multi;
- const char *const peer_info = tls_multi->peer_info;
struct options *o = &c->options;
/* ipv6 */
@@ -480,18 +478,10 @@ prepare_push_reply(struct context *c, struct gc_arena *gc,
0, gc));
}
- /* Send peer-id if client supports it */
- optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL;
- if (optstr)
+ if (tls_multi->use_peer_id)
{
- int proto = 0;
- int r = sscanf(optstr, "IV_PROTO=%d", &proto);
- if ((r == 1) && (proto >= 2))
- {
- push_option_fmt(gc, push_list, M_USAGE, "peer-id %d",
- tls_multi->peer_id);
- tls_multi->use_peer_id = true;
- }
+ push_option_fmt(gc, push_list, M_USAGE, "peer-id %d",
+ tls_multi->peer_id);
}
/*
* If server uses --auth-gen-token and we have an auth token
@@ -499,47 +489,11 @@ prepare_push_reply(struct context *c, struct gc_arena *gc,
*/
prepare_auth_token_push_reply(tls_multi, gc, push_list);
- /* Push cipher if client supports Negotiable Crypto Parameters */
- if (o->ncp_enabled)
- {
- /* if we have already created our key, we cannot *change* our own
- * cipher -> so log the fact and push the "what we have now" cipher
- * (so the client is always told what we expect it to use)
- */
- const struct tls_session *session = &tls_multi->session[TM_ACTIVE];
- if (session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized)
- {
- msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but "
- "server has already generated data channel keys, "
- "re-sending previously negotiated cipher '%s'",
- o->ciphername );
- }
- else
- {
- /*
- * Push the first cipher from --ncp-ciphers to the client that
- * the client announces to be supporting.
- */
- char *push_cipher = ncp_get_best_cipher(o->ncp_ciphers, o->ciphername,
- peer_info,
- tls_multi->remote_ciphername,
- &o->gc);
-
- if (push_cipher)
- {
- o->ciphername = push_cipher;
- }
- else
- {
- const char *peer_ciphers = tls_peer_ncp_list(peer_info, gc);
- msg(M_INFO, "PUSH: No common cipher between server and client."
- "Expect this connection not to work. "
- "Server ncp-ciphers: '%s', client supported ciphers '%s'",
- o->ncp_ciphers, peer_ciphers);
- }
- }
- push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername);
- }
+ /*
+ * Push the selected cipher, at this point the cipher has been
+ * already negotiated and been fixed
+ */
+ push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername);
return true;
}
@@ -794,9 +748,7 @@ process_incoming_push_request(struct context *c)
{
int ret = PUSH_MSG_ERROR;
-#ifdef ENABLE_ASYNC_PUSH
c->c2.push_request_received = true;
-#endif
if (tls_authentication_status(c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED)
{
const char *client_reason = tls_client_reason(c->c2.tls_multi);