0
0
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:
Steffan Karger 2016-06-28 23:35:00 +02:00 committed by Gert Doering
parent 49817bf0ad
commit d728ebeda8
9 changed files with 119 additions and 23 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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
};

View File

@ -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])

View File

@ -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)

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;