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>
... | ... |
@@ -4131,6 +4131,19 @@ Set |
4131 | 4131 |
to disable encryption. |
4132 | 4132 |
.\"********************************************************* |
4133 | 4133 |
.TP |
4134 |
+.B \-\-ncp\-ciphers cipher_list |
|
4135 |
+Restrict the allowed ciphers to be negotiated to the ciphers in |
|
4136 |
+.B cipher_list\fR. |
|
4137 |
+.B cipher_list |
|
4138 |
+is a colon-separated list of ciphers, and defaults to |
|
4139 |
+"AES-256-GCM:AES-128-GCM". |
|
4140 |
+.\"********************************************************* |
|
4141 |
+.TP |
|
4142 |
+.B \-\-ncp\-disable |
|
4143 |
+Disable "negotiable crypto parameters". This completely disables cipher |
|
4144 |
+negotiation. |
|
4145 |
+.\"********************************************************* |
|
4146 |
+.TP |
|
4134 | 4147 |
.B \-\-keysize n |
4135 | 4148 |
Size of cipher key in bits (optional). |
4136 | 4149 |
If unspecified, defaults to cipher-specific default. The |
... | ... |
@@ -1745,7 +1745,7 @@ options_hash_changed_or_zero(const struct md5_digest *a, |
1745 | 1745 |
} |
1746 | 1746 |
#endif /* P2MP */ |
1747 | 1747 |
|
1748 |
-void |
|
1748 |
+bool |
|
1749 | 1749 |
do_up (struct context *c, bool pulled_options, unsigned int option_types_found) |
1750 | 1750 |
{ |
1751 | 1751 |
if (!c->c2.do_up_ran) |
... | ... |
@@ -1753,7 +1753,13 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) |
1753 | 1753 |
reset_coarse_timers (c); |
1754 | 1754 |
|
1755 | 1755 |
if (pulled_options && option_types_found) |
1756 |
- do_deferred_options (c, option_types_found); |
|
1756 |
+ { |
|
1757 |
+ if (!do_deferred_options (c, option_types_found)) |
|
1758 |
+ { |
|
1759 |
+ msg (D_PUSH_ERRORS, "ERROR: Failed to apply push options"); |
|
1760 |
+ return false; |
|
1761 |
+ } |
|
1762 |
+ } |
|
1757 | 1763 |
|
1758 | 1764 |
/* if --up-delay specified, open tun, do ifconfig, and run up script now */ |
1759 | 1765 |
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) |
1808 | 1808 |
|
1809 | 1809 |
c->c2.do_up_ran = true; |
1810 | 1810 |
} |
1811 |
+ return true; |
|
1811 | 1812 |
} |
1812 | 1813 |
|
1813 | 1814 |
/* |
... | ... |
@@ -1825,7 +1832,6 @@ pull_permission_mask (const struct context *c) |
1825 | 1825 |
| OPT_P_SHAPER |
1826 | 1826 |
| OPT_P_TIMER |
1827 | 1827 |
| OPT_P_COMP |
1828 |
- | OPT_P_CRYPTO |
|
1829 | 1828 |
| OPT_P_PERSIST |
1830 | 1829 |
| OPT_P_MESSAGES |
1831 | 1830 |
| OPT_P_EXPLICIT_NOTIFY |
... | ... |
@@ -1836,13 +1842,18 @@ pull_permission_mask (const struct context *c) |
1836 | 1836 |
if (!c->options.route_nopull) |
1837 | 1837 |
flags |= (OPT_P_ROUTE | OPT_P_IPWIN32); |
1838 | 1838 |
|
1839 |
+#ifdef ENABLE_CRYPTO |
|
1840 |
+ if (c->options.ncp_enabled) |
|
1841 |
+ flags |= OPT_P_NCP; |
|
1842 |
+#endif |
|
1843 |
+ |
|
1839 | 1844 |
return flags; |
1840 | 1845 |
} |
1841 | 1846 |
|
1842 | 1847 |
/* |
1843 | 1848 |
* Handle non-tun-related pulled options. |
1844 | 1849 |
*/ |
1845 |
-void |
|
1850 |
+bool |
|
1846 | 1851 |
do_deferred_options (struct context *c, const unsigned int found) |
1847 | 1852 |
{ |
1848 | 1853 |
if (found & OPT_P_MESSAGES) |
... | ... |
@@ -1934,15 +1945,18 @@ do_deferred_options (struct context *c, const unsigned int found) |
1934 | 1934 |
if (c->options.pull) |
1935 | 1935 |
{ |
1936 | 1936 |
struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; |
1937 |
- if (found & OPT_P_CRYPTO) |
|
1937 |
+ if (found & OPT_P_NCP) |
|
1938 | 1938 |
msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); |
1939 | 1939 |
/* Do not regenerate keys if server sends an extra push request */ |
1940 |
- if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized) |
|
1940 |
+ if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized && |
|
1941 |
+ !tls_session_update_crypto_params(session, &c->options, &c->c2.frame)) |
|
1941 | 1942 |
{ |
1942 |
- tls_session_update_crypto_params(session, &c->options, &c->c2.frame); |
|
1943 |
+ msg (D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); |
|
1944 |
+ return false; |
|
1943 | 1945 |
} |
1944 | 1946 |
} |
1945 | 1947 |
#endif |
1948 |
+ return true; |
|
1946 | 1949 |
} |
1947 | 1950 |
|
1948 | 1951 |
/* |
... | ... |
@@ -2272,6 +2286,9 @@ do_init_crypto_tls_c1 (struct context *c) |
2272 | 2272 |
&c->c1.ks.tls_auth_key, file, options->key_direction, flags); |
2273 | 2273 |
} |
2274 | 2274 |
|
2275 |
+ c->c1.ciphername = options->ciphername; |
|
2276 |
+ c->c1.authname = options->authname; |
|
2277 |
+ |
|
2275 | 2278 |
#if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */ |
2276 | 2279 |
if (options->priv_key_file_inline) |
2277 | 2280 |
{ |
... | ... |
@@ -2348,6 +2365,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) |
2348 | 2348 |
to.replay_window = options->replay_window; |
2349 | 2349 |
to.replay_time = options->replay_time; |
2350 | 2350 |
to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto); |
2351 |
+ to.config_ciphername = c->c1.ciphername; |
|
2352 |
+ to.config_authname = c->c1.authname; |
|
2353 |
+ to.ncp_enabled = options->ncp_enabled; |
|
2351 | 2354 |
to.transition_window = options->transition_window; |
2352 | 2355 |
to.handshake_window = options->handshake_window; |
2353 | 2356 |
to.packet_timeout = options->tls_timeout; |
... | ... |
@@ -81,7 +81,7 @@ bool do_test_crypto (const struct options *o); |
81 | 81 |
|
82 | 82 |
void context_gc_free (struct context *c); |
83 | 83 |
|
84 |
-void do_up (struct context *c, |
|
84 |
+bool do_up (struct context *c, |
|
85 | 85 |
bool pulled_options, |
86 | 86 |
unsigned int option_types_found); |
87 | 87 |
|
... | ... |
@@ -91,7 +91,7 @@ const char *format_common_name (struct context *c, struct gc_arena *gc); |
91 | 91 |
|
92 | 92 |
void reset_coarse_timers (struct context *c); |
93 | 93 |
|
94 |
-void do_deferred_options (struct context *c, const unsigned int found); |
|
94 |
+bool do_deferred_options (struct context *c, const unsigned int found); |
|
95 | 95 |
|
96 | 96 |
void inherit_context_child (struct context *dest, |
97 | 97 |
const struct context *src); |
... | ... |
@@ -210,6 +210,9 @@ struct context_1 |
210 | 210 |
struct user_pass *auth_user_pass; |
211 | 211 |
/**< Username and password for |
212 | 212 |
* authentication. */ |
213 |
+ |
|
214 |
+ const char *ciphername; /**< Data channel cipher from config file */ |
|
215 |
+ const char *authname; /**< Data channel auth from config file */ |
|
213 | 216 |
#endif |
214 | 217 |
}; |
215 | 218 |
|
... | ... |
@@ -522,6 +522,8 @@ static const char usage_message[] = |
522 | 522 |
"--cipher alg : Encrypt packets with cipher algorithm alg\n" |
523 | 523 |
" (default=%s).\n" |
524 | 524 |
" Set alg=none to disable encryption.\n" |
525 |
+ "--ncp-ciphers list : List of ciphers that are allowed to be negotiated.\n" |
|
526 |
+ "--ncp-disable : Disable cipher negotiation.\n" |
|
525 | 527 |
"--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n" |
526 | 528 |
" nonce_secret_len=nsl. Set alg=none to disable PRNG.\n" |
527 | 529 |
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH |
... | ... |
@@ -829,6 +831,12 @@ init_options (struct options *o, const bool init_gc) |
829 | 829 |
#ifdef ENABLE_CRYPTO |
830 | 830 |
o->ciphername = "BF-CBC"; |
831 | 831 |
o->ciphername_defined = true; |
832 |
+#ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */ |
|
833 |
+ o->ncp_enabled = true; |
|
834 |
+#else |
|
835 |
+ o->ncp_enabled = false; |
|
836 |
+#endif |
|
837 |
+ o->ncp_ciphers = "AES-256-GCM:AES-128-GCM"; |
|
832 | 838 |
o->authname = "SHA1"; |
833 | 839 |
o->authname_defined = true; |
834 | 840 |
o->prng_hash = "SHA1"; |
... | ... |
@@ -6637,7 +6645,7 @@ add_option (struct options *options, |
6637 | 6637 |
} |
6638 | 6638 |
else if (streq (p[0], "auth") && p[1] && !p[2]) |
6639 | 6639 |
{ |
6640 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6640 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6641 | 6641 |
options->authname_defined = true; |
6642 | 6642 |
options->authname = p[1]; |
6643 | 6643 |
if (streq (options->authname, "none")) |
... | ... |
@@ -6648,12 +6656,12 @@ add_option (struct options *options, |
6648 | 6648 |
} |
6649 | 6649 |
else if (streq (p[0], "auth") && !p[1]) |
6650 | 6650 |
{ |
6651 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6651 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6652 | 6652 |
options->authname_defined = true; |
6653 | 6653 |
} |
6654 | 6654 |
else if (streq (p[0], "cipher") && p[1] && !p[2]) |
6655 | 6655 |
{ |
6656 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6656 |
+ VERIFY_PERMISSION (OPT_P_NCP); |
|
6657 | 6657 |
options->ciphername_defined = true; |
6658 | 6658 |
options->ciphername = p[1]; |
6659 | 6659 |
if (streq (options->ciphername, "none")) |
... | ... |
@@ -6664,12 +6672,22 @@ add_option (struct options *options, |
6664 | 6664 |
} |
6665 | 6665 |
else if (streq (p[0], "cipher") && !p[1]) |
6666 | 6666 |
{ |
6667 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6667 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6668 | 6668 |
options->ciphername_defined = true; |
6669 | 6669 |
} |
6670 |
+ else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2]) |
|
6671 |
+ { |
|
6672 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6673 |
+ options->ncp_ciphers = p[1]; |
|
6674 |
+ } |
|
6675 |
+ else if (streq (p[0], "ncp-disable") && !p[1]) |
|
6676 |
+ { |
|
6677 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6678 |
+ options->ncp_enabled = false; |
|
6679 |
+ } |
|
6670 | 6680 |
else if (streq (p[0], "prng") && p[1] && !p[3]) |
6671 | 6681 |
{ |
6672 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6682 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6673 | 6683 |
if (streq (p[1], "none")) |
6674 | 6684 |
options->prng_hash = NULL; |
6675 | 6685 |
else |
... | ... |
@@ -6691,12 +6709,12 @@ add_option (struct options *options, |
6691 | 6691 |
} |
6692 | 6692 |
else if (streq (p[0], "no-replay") && !p[1]) |
6693 | 6693 |
{ |
6694 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6694 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6695 | 6695 |
options->replay = false; |
6696 | 6696 |
} |
6697 | 6697 |
else if (streq (p[0], "replay-window") && !p[3]) |
6698 | 6698 |
{ |
6699 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6699 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6700 | 6700 |
if (p[1]) |
6701 | 6701 |
{ |
6702 | 6702 |
int replay_window; |
... | ... |
@@ -6736,12 +6754,12 @@ add_option (struct options *options, |
6736 | 6736 |
} |
6737 | 6737 |
else if (streq (p[0], "mute-replay-warnings") && !p[1]) |
6738 | 6738 |
{ |
6739 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6739 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6740 | 6740 |
options->mute_replay_warnings = true; |
6741 | 6741 |
} |
6742 | 6742 |
else if (streq (p[0], "no-iv") && !p[1]) |
6743 | 6743 |
{ |
6744 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6744 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6745 | 6745 |
options->use_iv = false; |
6746 | 6746 |
} |
6747 | 6747 |
else if (streq (p[0], "replay-persist") && p[1] && !p[2]) |
... | ... |
@@ -6771,7 +6789,7 @@ add_option (struct options *options, |
6771 | 6771 |
{ |
6772 | 6772 |
int keysize; |
6773 | 6773 |
|
6774 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6774 |
+ VERIFY_PERMISSION (OPT_P_NCP); |
|
6775 | 6775 |
keysize = atoi (p[1]) / 8; |
6776 | 6776 |
if (keysize < 0 || keysize > MAX_CIPHER_KEY_LENGTH) |
6777 | 6777 |
{ |
... | ... |
@@ -6800,7 +6818,7 @@ add_option (struct options *options, |
6800 | 6800 |
} |
6801 | 6801 |
else if (streq (p[0], "ecdh-curve") && p[1] && !p[2]) |
6802 | 6802 |
{ |
6803 |
- VERIFY_PERMISSION (OPT_P_CRYPTO); |
|
6803 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
6804 | 6804 |
options->ecdh_curve= p[1]; |
6805 | 6805 |
} |
6806 | 6806 |
else if (streq (p[0], "tls-server") && !p[1]) |
... | ... |
@@ -471,6 +471,8 @@ struct options |
471 | 471 |
int key_direction; |
472 | 472 |
bool ciphername_defined; |
473 | 473 |
const char *ciphername; |
474 |
+ bool ncp_enabled; |
|
475 |
+ const char *ncp_ciphers; |
|
474 | 476 |
bool authname_defined; |
475 | 477 |
const char *authname; |
476 | 478 |
int keysize; |
... | ... |
@@ -615,7 +617,7 @@ struct options |
615 | 615 |
#define OPT_P_PERSIST_IP (1<<9) |
616 | 616 |
#define OPT_P_COMP (1<<10) /* TODO */ |
617 | 617 |
#define OPT_P_MESSAGES (1<<11) |
618 |
-#define OPT_P_CRYPTO (1<<12) /* TODO */ |
|
618 |
+#define OPT_P_NCP (1<<12) /**< Negotiable crypto parameters */ |
|
619 | 619 |
#define OPT_P_TLS_PARMS (1<<13) /* TODO */ |
620 | 620 |
#define OPT_P_MTU (1<<14) /* TODO */ |
621 | 621 |
#define OPT_P_NICE (1<<15) |
... | ... |
@@ -239,11 +239,20 @@ incoming_push_message (struct context *c, const struct buffer *buffer) |
239 | 239 |
{ |
240 | 240 |
c->options.push_option_types_found |= option_types_found; |
241 | 241 |
|
242 |
+ /* delay bringing tun/tap up until --push parms received from remote */ |
|
242 | 243 |
if (status == PUSH_MSG_REPLY) |
243 |
- do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */ |
|
244 |
+ { |
|
245 |
+ if (!do_up (c, true, c->options.push_option_types_found)) |
|
246 |
+ { |
|
247 |
+ msg (D_PUSH_ERRORS, "Failed to open tun/tap interface"); |
|
248 |
+ register_signal (c, SIGUSR1, "do_up-failed"); |
|
249 |
+ goto cleanup; |
|
250 |
+ } |
|
251 |
+ } |
|
244 | 252 |
event_timeout_clear (&c->c2.push_request_interval); |
245 | 253 |
} |
246 | 254 |
|
255 |
+cleanup: |
|
247 | 256 |
gc_free (&gc); |
248 | 257 |
} |
249 | 258 |
|
... | ... |
@@ -1640,6 +1640,24 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) { |
1640 | 1640 |
} |
1641 | 1641 |
} |
1642 | 1642 |
|
1643 |
+static bool |
|
1644 |
+item_in_list(const char *item, const char *list) |
|
1645 |
+{ |
|
1646 |
+ char *tmp_ciphers = string_alloc (list, NULL); |
|
1647 |
+ char *tmp_ciphers_orig = tmp_ciphers; |
|
1648 |
+ |
|
1649 |
+ const char *token = strtok (tmp_ciphers, ":"); |
|
1650 |
+ while(token) |
|
1651 |
+ { |
|
1652 |
+ if (0 == strcmp (token, item)) |
|
1653 |
+ break; |
|
1654 |
+ token = strtok (NULL, ":"); |
|
1655 |
+ } |
|
1656 |
+ free(tmp_ciphers_orig); |
|
1657 |
+ |
|
1658 |
+ return token != NULL; |
|
1659 |
+} |
|
1660 |
+ |
|
1643 | 1661 |
bool |
1644 | 1662 |
tls_session_update_crypto_params(struct tls_session *session, |
1645 | 1663 |
const struct options *options, struct frame *frame) |
... | ... |
@@ -1650,6 +1668,15 @@ tls_session_update_crypto_params(struct tls_session *session, |
1650 | 1650 |
ASSERT (!session->opt->server); |
1651 | 1651 |
ASSERT (ks->authenticated); |
1652 | 1652 |
|
1653 |
+ if (0 != strcmp(options->ciphername, session->opt->config_ciphername) && |
|
1654 |
+ !item_in_list(options->ciphername, options->ncp_ciphers)) |
|
1655 |
+ { |
|
1656 |
+ msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s", |
|
1657 |
+ options->ciphername, session->opt->config_ciphername, |
|
1658 |
+ options->ncp_ciphers); |
|
1659 |
+ return false; |
|
1660 |
+ } |
|
1661 |
+ |
|
1653 | 1662 |
init_key_type (&session->opt->key_type, options->ciphername, |
1654 | 1663 |
options->ciphername_defined, options->authname, options->authname_defined, |
1655 | 1664 |
options->keysize, true, true); |
... | ... |
@@ -1931,7 +1958,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) |
1931 | 1931 |
buf_printf(&out, "IV_PROTO=2\n"); |
1932 | 1932 |
|
1933 | 1933 |
/* support for Negotiable Crypto Paramters */ |
1934 |
- if (session->opt->pull) |
|
1934 |
+ if (session->opt->ncp_enabled && session->opt->pull) |
|
1935 | 1935 |
buf_printf(&out, "IV_NCP=2\n"); |
1936 | 1936 |
|
1937 | 1937 |
/* push compression status */ |
... | ... |
@@ -273,6 +273,10 @@ struct tls_options |
273 | 273 |
int replay_time; /* --replay-window parm */ |
274 | 274 |
bool tcp_mode; |
275 | 275 |
|
276 |
+ const char *config_ciphername; |
|
277 |
+ const char *config_authname; |
|
278 |
+ bool ncp_enabled; |
|
279 |
+ |
|
276 | 280 |
/* packet authentication for TLS handshake */ |
277 | 281 |
struct crypto_options tls_auth; |
278 | 282 |
|