to disable encryption.
.\"*********************************************************
.TP
+.B \-\-ncp\-ciphers cipher_list
+Restrict the allowed ciphers to be negotiated to the ciphers in
+.B cipher_list\fR.
+.B cipher_list
+is a colon-separated list of ciphers, and defaults to
+"AES-256-GCM:AES-128-GCM".
+.\"*********************************************************
+.TP
+.B \-\-ncp\-disable
+Disable "negotiable crypto parameters". This completely disables cipher
+negotiation.
+.\"*********************************************************
+.TP
.B \-\-keysize n
Size of cipher key in bits (optional).
If unspecified, defaults to cipher-specific default. The
}
#endif /* P2MP */
-void
+bool
do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
{
if (!c->c2.do_up_ran)
reset_coarse_timers (c);
if (pulled_options && option_types_found)
- do_deferred_options (c, option_types_found);
+ {
+ if (!do_deferred_options (c, option_types_found))
+ {
+ msg (D_PUSH_ERRORS, "ERROR: Failed to apply push options");
+ return false;
+ }
+ }
/* if --up-delay specified, open tun, do ifconfig, and run up script now */
if (c->options.up_delay || PULL_DEFINED (&c->options))
c->c2.do_up_ran = true;
}
+ return true;
}
/*
| OPT_P_SHAPER
| OPT_P_TIMER
| OPT_P_COMP
- | OPT_P_CRYPTO
| OPT_P_PERSIST
| OPT_P_MESSAGES
| OPT_P_EXPLICIT_NOTIFY
if (!c->options.route_nopull)
flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
+#ifdef ENABLE_CRYPTO
+ if (c->options.ncp_enabled)
+ flags |= OPT_P_NCP;
+#endif
+
return flags;
}
/*
* Handle non-tun-related pulled options.
*/
-void
+bool
do_deferred_options (struct context *c, const unsigned int found)
{
if (found & OPT_P_MESSAGES)
if (c->options.pull)
{
struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
- if (found & OPT_P_CRYPTO)
+ if (found & OPT_P_NCP)
msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified");
/* Do not regenerate keys if server sends an extra push request */
- if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized)
+ if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized &&
+ !tls_session_update_crypto_params(session, &c->options, &c->c2.frame))
{
- tls_session_update_crypto_params(session, &c->options, &c->c2.frame);
+ msg (D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options");
+ return false;
}
}
#endif
+ return true;
}
/*
&c->c1.ks.tls_auth_key, file, options->key_direction, flags);
}
+ c->c1.ciphername = options->ciphername;
+ c->c1.authname = options->authname;
+
#if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */
if (options->priv_key_file_inline)
{
to.replay_window = options->replay_window;
to.replay_time = options->replay_time;
to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto);
+ to.config_ciphername = c->c1.ciphername;
+ to.config_authname = c->c1.authname;
+ to.ncp_enabled = options->ncp_enabled;
to.transition_window = options->transition_window;
to.handshake_window = options->handshake_window;
to.packet_timeout = options->tls_timeout;
void context_gc_free (struct context *c);
-void do_up (struct context *c,
+bool do_up (struct context *c,
bool pulled_options,
unsigned int option_types_found);
void reset_coarse_timers (struct context *c);
-void do_deferred_options (struct context *c, const unsigned int found);
+bool do_deferred_options (struct context *c, const unsigned int found);
void inherit_context_child (struct context *dest,
const struct context *src);
struct user_pass *auth_user_pass;
/**< Username and password for
* authentication. */
+
+ const char *ciphername; /**< Data channel cipher from config file */
+ const char *authname; /**< Data channel auth from config file */
#endif
};
"--cipher alg : Encrypt packets with cipher algorithm alg\n"
" (default=%s).\n"
" Set alg=none to disable encryption.\n"
+ "--ncp-ciphers list : List of ciphers that are allowed to be negotiated.\n"
+ "--ncp-disable : Disable cipher negotiation.\n"
"--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n"
" nonce_secret_len=nsl. Set alg=none to disable PRNG.\n"
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH
#ifdef ENABLE_CRYPTO
o->ciphername = "BF-CBC";
o->ciphername_defined = true;
+#ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */
+ o->ncp_enabled = true;
+#else
+ o->ncp_enabled = false;
+#endif
+ o->ncp_ciphers = "AES-256-GCM:AES-128-GCM";
o->authname = "SHA1";
o->authname_defined = true;
o->prng_hash = "SHA1";
}
else if (streq (p[0], "auth") && p[1] && !p[2])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->authname_defined = true;
options->authname = p[1];
if (streq (options->authname, "none"))
}
else if (streq (p[0], "auth") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->authname_defined = true;
}
else if (streq (p[0], "cipher") && p[1] && !p[2])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_NCP);
options->ciphername_defined = true;
options->ciphername = p[1];
if (streq (options->ciphername, "none"))
}
else if (streq (p[0], "cipher") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->ciphername_defined = true;
}
+ else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->ncp_ciphers = p[1];
+ }
+ else if (streq (p[0], "ncp-disable") && !p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->ncp_enabled = false;
+ }
else if (streq (p[0], "prng") && p[1] && !p[3])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "none"))
options->prng_hash = NULL;
else
}
else if (streq (p[0], "no-replay") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->replay = false;
}
else if (streq (p[0], "replay-window") && !p[3])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
if (p[1])
{
int replay_window;
}
else if (streq (p[0], "mute-replay-warnings") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->mute_replay_warnings = true;
}
else if (streq (p[0], "no-iv") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->use_iv = false;
}
else if (streq (p[0], "replay-persist") && p[1] && !p[2])
{
int keysize;
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_NCP);
keysize = atoi (p[1]) / 8;
if (keysize < 0 || keysize > MAX_CIPHER_KEY_LENGTH)
{
}
else if (streq (p[0], "ecdh-curve") && p[1] && !p[2])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->ecdh_curve= p[1];
}
else if (streq (p[0], "tls-server") && !p[1])
int key_direction;
bool ciphername_defined;
const char *ciphername;
+ bool ncp_enabled;
+ const char *ncp_ciphers;
bool authname_defined;
const char *authname;
int keysize;
#define OPT_P_PERSIST_IP (1<<9)
#define OPT_P_COMP (1<<10) /* TODO */
#define OPT_P_MESSAGES (1<<11)
-#define OPT_P_CRYPTO (1<<12) /* TODO */
+#define OPT_P_NCP (1<<12) /**< Negotiable crypto parameters */
#define OPT_P_TLS_PARMS (1<<13) /* TODO */
#define OPT_P_MTU (1<<14) /* TODO */
#define OPT_P_NICE (1<<15)
{
c->options.push_option_types_found |= option_types_found;
+ /* delay bringing tun/tap up until --push parms received from remote */
if (status == PUSH_MSG_REPLY)
- do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */
+ {
+ 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;
+ }
+ }
event_timeout_clear (&c->c2.push_request_interval);
}
+cleanup:
gc_free (&gc);
}
}
}
+static bool
+item_in_list(const char *item, const char *list)
+{
+ char *tmp_ciphers = string_alloc (list, NULL);
+ char *tmp_ciphers_orig = tmp_ciphers;
+
+ const char *token = strtok (tmp_ciphers, ":");
+ while(token)
+ {
+ if (0 == strcmp (token, item))
+ break;
+ token = strtok (NULL, ":");
+ }
+ free(tmp_ciphers_orig);
+
+ return token != NULL;
+}
+
bool
tls_session_update_crypto_params(struct tls_session *session,
const struct options *options, struct frame *frame)
ASSERT (!session->opt->server);
ASSERT (ks->authenticated);
+ if (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->ciphername, session->opt->config_ciphername,
+ options->ncp_ciphers);
+ return false;
+ }
+
init_key_type (&session->opt->key_type, options->ciphername,
options->ciphername_defined, options->authname, options->authname_defined,
options->keysize, true, true);
buf_printf(&out, "IV_PROTO=2\n");
/* support for Negotiable Crypto Paramters */
- if (session->opt->pull)
+ if (session->opt->ncp_enabled && session->opt->pull)
buf_printf(&out, "IV_NCP=2\n");
/* push compression status */
int replay_time; /* --replay-window parm */
bool tcp_mode;
+ const char *config_ciphername;
+ const char *config_authname;
+ bool ncp_enabled;
+
/* packet authentication for TLS handshake */
struct crypto_options tls_auth;