Http proxy passwords can be specified with the inline file option
http-proxy-user-pass
+Cipher negotiation
+ Data channel ciphers are now by default negotiated. If a client advertises
+ support for Negotiable Crypto Parameters (NCP), the server will choose a
+ cipher (by default AES-256-GCM) for the data channel, and tell the client
+ to use that cipher. Data channel cipher negotiation can be controlled
+ using --ncp-ciphers and --ncp-disable.
+
User-visible Changes
--------------------
time in seconds to wait between reconnection attempts when an exponential
backoff is triggered due to repeated retries. Default = 300 seconds.
+- Data channel cipher negotiation (see New features section) can override
+ ciphers configured in the config file. Use --ncp-disable if you don't want
+ that.
+
+
Maintainer-visible changes
--------------------------
- OpenVPN no longer supports building with crypto support, but without TLS
.B cipher_list
is a colon-separated list of ciphers, and defaults to
"AES-256-GCM:AES-128-GCM".
+
+For servers, the first cipher from
+.B cipher_list
+will be pushed to clients that support cipher negotiation.
.\"*********************************************************
.TP
.B \-\-ncp\-disable
/* In short form, unique datagram identifier is 32 bits, in long form 64 bits */
packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher);
- /* Compute MTU parameters (postpone if we pull options) */
- if (c->options.pull)
+ /* Compute MTU parameters (postpone if we push/pull options) */
+ if (c->options.pull || c->options.mode == MODE_SERVER)
{
/* Account for worst-case crypto overhead before allocating buffers */
frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead());
to.renegotiate_packets = options->renegotiate_packets;
to.renegotiate_seconds = options->renegotiate_seconds;
to.single_session = options->single_session;
+ to.mode = options->mode;
to.pull = options->pull;
#ifdef ENABLE_PUSH_PEER_INFO
if (options->push_peer_info) /* all there is */
if (!do_up (c, true, c->options.push_option_types_found))
{
msg (D_PUSH_ERRORS, "Failed to open tun/tap interface");
- register_signal (c, SIGUSR1, "do_up-failed");
- goto cleanup;
+ goto error;
}
}
event_timeout_clear (&c->c2.push_request_interval);
}
+ else if (status == PUSH_MSG_REQUEST)
+ {
+ if (c->options.mode == MODE_SERVER)
+ {
+ struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
+ /* Do not regenerate keys if client send a second push request */
+ if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized &&
+ !tls_session_update_crypto_params (session, &c->options,
+ &c->c2.frame))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
+ goto error;
+ }
+ }
+ }
+ goto cleanup;
+error:
+ register_signal (c, SIGUSR1, "process-push-msg-failed");
cleanup:
gc_free (&gc);
}
}
/* Push cipher if client supports Negotiable Crypto Parameters */
- optstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL;
- if (optstr)
+ if (tls_peer_info_ncp_ver (peer_info) >= 2 && o->ncp_enabled)
{
- int ncp = 0;
- int r = sscanf(optstr, "IV_NCP=%d", &ncp);
- if ((r == 1) && (ncp == 2))
- {
- push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
- }
+ /* Push the first cipher from --ncp-ciphers to the client.
+ * TODO: actual negotiation, instead of server dictatorship. */
+ char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc);
+ o->ciphername = strtok (push_cipher, ":");
+ push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
}
return true;
}
bool ret = false;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- ASSERT (!session->opt->server);
ASSERT (ks->authenticated);
- if (0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
+ if (!session->opt->server &&
+ 0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
!item_in_list(options->ciphername, options->ncp_ciphers))
{
msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s",
options->ce.tun_mtu_defined, options->ce.tun_mtu);
frame_print (frame, D_MTU_INFO, "Data Channel MTU parms");
+ const struct session_id *client_sid = session->opt->server ?
+ &ks->session_id_remote : &session->session_id;
+ const struct session_id *server_sid = !session->opt->server ?
+ &ks->session_id_remote : &session->session_id;
if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
- &session->opt->key_type,
- ks->key_src,
- &session->session_id,
- &ks->session_id_remote,
- false))
+ &session->opt->key_type, ks->key_src, client_sid, server_sid,
+ session->opt->server))
{
msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
goto cleanup;
buf_printf(&out, "IV_PROTO=2\n");
/* support for Negotiable Crypto Paramters */
- if (session->opt->ncp_enabled && session->opt->pull)
- buf_printf(&out, "IV_NCP=2\n");
+ if (session->opt->ncp_enabled &&
+ (session->opt->mode == MODE_SERVER || session->opt->pull))
+ {
+ buf_printf(&out, "IV_NCP=2\n");
+ }
/* push compression status */
#ifdef USE_COMP
if (!push_peer_info (buf, session))
goto error;
- /*
- * generate tunnel keys if server
+ /* Generate tunnel keys if we're a TLS server.
+ * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key
+ * generation is postponed until after the pull/push, so we can process pushed
+ * cipher directives.
*/
- if (session->opt->server)
+ if (session->opt->server && !(session->opt->ncp_enabled &&
+ session->opt->mode == MODE_SERVER && ks->key_id <= 0))
{
if (ks->authenticated)
{
multi->peer_info = read_string_alloc (buf);
if ( multi->peer_info )
output_peer_info_env (session->opt->es, multi->peer_info);
+
+ if (tls_peer_info_ncp_ver (multi->peer_info) < 2)
+ {
+ /* Peer does not support NCP */
+ session->opt->ncp_enabled = false;
+ }
#endif
if (tls_session_user_pass_enabled(session))
gc_free (&gc);
}
+int
+tls_peer_info_ncp_ver(const char *peer_info)
+{
+ const char *ncpstr = peer_info ? strstr (peer_info, "IV_NCP=") : NULL;
+ if (ncpstr)
+ {
+ int ncp = 0;
+ int r = sscanf(ncpstr, "IV_NCP=%d", &ncp);
+ if (r == 1)
+ return ncp;
+ }
+ return 0;
+}
+
/*
* Dump a human-readable rendition of an openvpn packet
* into a garbage collectable string which is returned.
}
#endif
+/**
+ * Return the Negotiable Crypto Parameters version advertised in the peer info
+ * string, or 0 if none specified.
+ */
+int tls_peer_info_ncp_ver(const char *peer_info);
+
/*
* inline functions
*/
#ifdef ENABLE_OCC
bool disable_occ;
#endif
+ int mode;
bool pull;
#ifdef ENABLE_PUSH_PEER_INFO
int push_peer_info_detail;