mirror of
https://github.com/OpenVPN/openvpn.git
synced 2024-09-20 03:52:28 +02:00
Add options to restrict cipher negotiation
Add --ncp-disable to completely disable cipher negotiation, and --ncp-ciphers to specify which ciphers to accept from the server. v2: * fix --disable-crypto builds * use register_signal() instead of operating directly on c->sig * add man-page entry for new options v3: * rebased on client-side NCP v3 v4: * rebased on client-side NCP v4 Signed-off-by: Steffan Karger <steffan@karger.me> Acked-by: Arne Schwabe <arne@rfc2549.org> Acked-by: Gert Doering <gert@greenie.muc.de> Message-Id: <1467149700-10042-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/12008 Signed-off-by: Gert Doering <gert@greenie.muc.de>
This commit is contained in:
parent
49817bf0ad
commit
d728ebeda8
@ -4131,6 +4131,19 @@ Set
|
||||
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
|
||||
|
@ -1745,7 +1745,7 @@ options_hash_changed_or_zero(const struct md5_digest *a,
|
||||
}
|
||||
#endif /* P2MP */
|
||||
|
||||
void
|
||||
bool
|
||||
do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
|
||||
{
|
||||
if (!c->c2.do_up_ran)
|
||||
@ -1753,7 +1753,13 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
|
||||
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))
|
||||
@ -1808,6 +1814,7 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
|
||||
|
||||
c->c2.do_up_ran = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1825,7 +1832,6 @@ pull_permission_mask (const struct context *c)
|
||||
| OPT_P_SHAPER
|
||||
| OPT_P_TIMER
|
||||
| OPT_P_COMP
|
||||
| OPT_P_CRYPTO
|
||||
| OPT_P_PERSIST
|
||||
| OPT_P_MESSAGES
|
||||
| OPT_P_EXPLICIT_NOTIFY
|
||||
@ -1836,13 +1842,18 @@ pull_permission_mask (const struct context *c)
|
||||
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)
|
||||
@ -1934,15 +1945,18 @@ do_deferred_options (struct context *c, const unsigned int found)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2272,6 +2286,9 @@ do_init_crypto_tls_c1 (struct context *c)
|
||||
&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)
|
||||
{
|
||||
@ -2348,6 +2365,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
|
||||
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;
|
||||
|
@ -81,7 +81,7 @@ bool do_test_crypto (const struct options *o);
|
||||
|
||||
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);
|
||||
|
||||
@ -91,7 +91,7 @@ const char *format_common_name (struct context *c, struct gc_arena *gc);
|
||||
|
||||
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);
|
||||
|
@ -210,6 +210,9 @@ struct context_1
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -522,6 +522,8 @@ static const char usage_message[] =
|
||||
"--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
|
||||
@ -829,6 +831,12 @@ init_options (struct options *o, const bool init_gc)
|
||||
#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";
|
||||
@ -6637,7 +6645,7 @@ add_option (struct options *options,
|
||||
}
|
||||
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"))
|
||||
@ -6648,12 +6656,12 @@ add_option (struct options *options,
|
||||
}
|
||||
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"))
|
||||
@ -6664,12 +6672,22 @@ add_option (struct options *options,
|
||||
}
|
||||
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
|
||||
@ -6691,12 +6709,12 @@ add_option (struct options *options,
|
||||
}
|
||||
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;
|
||||
@ -6736,12 +6754,12 @@ add_option (struct options *options,
|
||||
}
|
||||
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])
|
||||
@ -6771,7 +6789,7 @@ add_option (struct options *options,
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -6800,7 +6818,7 @@ add_option (struct options *options,
|
||||
}
|
||||
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])
|
||||
|
@ -471,6 +471,8 @@ struct options
|
||||
int key_direction;
|
||||
bool ciphername_defined;
|
||||
const char *ciphername;
|
||||
bool ncp_enabled;
|
||||
const char *ncp_ciphers;
|
||||
bool authname_defined;
|
||||
const char *authname;
|
||||
int keysize;
|
||||
@ -615,7 +617,7 @@ struct options
|
||||
#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)
|
||||
|
@ -239,11 +239,20 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1640,6 +1640,24 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) {
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1650,6 +1668,15 @@ tls_session_update_crypto_params(struct tls_session *session,
|
||||
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);
|
||||
@ -1931,7 +1958,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
|
||||
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 */
|
||||
|
@ -273,6 +273,10 @@ struct tls_options
|
||||
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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user