From 57d6f103f378b927b9e0054b022b5b8b442973b8 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sat, 7 Jul 2018 17:04:21 +0800 Subject: [PATCH] make tls-auth and tls-crypt per-connection-block options Different VPN servers may use different tls-auth/crypt keys. For this reason it is convenient to make tls-auth/crypt per-connection-block options so that the user is allowed to specify one key per remote. If no tls-auth/crypt option is specified in a given connection block, the global settings, if any, are used. Trac: #720 Cc: Steffan Karger Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20180707090421.25953-2-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg17226.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 3 + src/openvpn/init.c | 18 ++--- src/openvpn/options.c | 173 +++++++++++++++++++++++++++++------------- src/openvpn/options.h | 9 +++ 4 files changed, 142 insertions(+), 61 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 46ea58b68..f01b48b69 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -361,6 +361,7 @@ block: .B fragment, .B http\-proxy, .B http\-proxy\-option, +.B key\-direction, .B link\-mtu, .B local, .B lport, @@ -372,6 +373,8 @@ block: .B remote, .B rport, .B socks\-proxy, +.B tls\-auth, +.B tls\-crypt, .B tun\-mtu and .B tun\-mtu\-extra. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 805344444..f432106e3 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2508,7 +2508,7 @@ do_init_tls_wrap_key(struct context *c) const struct options *options = &c->options; /* TLS handshake authentication (--tls-auth) */ - if (options->tls_auth_file) + if (options->ce.tls_auth_file) { /* Initialize key_type for tls-auth with auth only */ CLEAR(c->c1.ks.tls_auth_key_type); @@ -2526,18 +2526,18 @@ do_init_tls_wrap_key(struct context *c) crypto_read_openvpn_key(&c->c1.ks.tls_auth_key_type, &c->c1.ks.tls_wrap_key, - options->tls_auth_file, - options->tls_auth_file_inline, - options->key_direction, + options->ce.tls_auth_file, + options->ce.tls_auth_file_inline, + options->ce.key_direction, "Control Channel Authentication", "tls-auth"); } /* TLS handshake encryption+authentication (--tls-crypt) */ - if (options->tls_crypt_file) + if (options->ce.tls_crypt_file) { tls_crypt_init_key(&c->c1.ks.tls_wrap_key, - options->tls_crypt_file, - options->tls_crypt_inline, options->tls_server); + options->ce.tls_crypt_file, + options->ce.tls_crypt_inline, options->tls_server); } } @@ -2807,7 +2807,7 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) #endif /* TLS handshake authentication (--tls-auth) */ - if (options->tls_auth_file) + if (options->ce.tls_auth_file) { to.tls_wrap.mode = TLS_WRAP_AUTH; to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; @@ -2818,7 +2818,7 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) } /* TLS handshake encryption (--tls-crypt) */ - if (options->tls_crypt_file) + if (options->ce.tls_crypt_file) { to.tls_wrap.mode = TLS_WRAP_CRYPT; to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 78b941fe0..61fa98335 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1507,6 +1507,11 @@ show_connection_entry(const struct connection_entry *o) #ifdef ENABLE_OCC SHOW_INT(explicit_exit_notification); #endif + + SHOW_STR(tls_auth_file); + SHOW_PARM(key_direction, keydirection2ascii(o->key_direction, false, true), + "%s"); + SHOW_STR(tls_crypt_file); } @@ -1787,9 +1792,6 @@ show_settings(const struct options *o) SHOW_BOOL(push_peer_info); SHOW_BOOL(tls_exit); - SHOW_STR(tls_auth_file); - SHOW_STR(tls_crypt_file); - #ifdef ENABLE_PKCS11 { int i; @@ -2724,7 +2726,7 @@ options_postprocess_verify_ce(const struct options *options, const struct connec notnull(options->priv_key_file, "private key file (--key) or PKCS#12 file (--pkcs12)"); } } - if (options->tls_auth_file && options->tls_crypt_file) + if (ce->tls_auth_file && ce->tls_crypt_file) { msg(M_USAGE, "--tls-auth and --tls-crypt are mutually exclusive"); } @@ -2870,6 +2872,49 @@ options_postprocess_mutate_ce(struct options *o, struct connection_entry *ce) } } + /* + * Set per-connection block tls-auth/crypt fields if undefined. + * + * At the end only one of the two will be really set because the parser + * logic prevents configurations where both are set. + */ + if (!ce->tls_auth_file && !ce->tls_crypt_file) + { + ce->tls_auth_file = o->tls_auth_file; + ce->tls_auth_file_inline = o->tls_auth_file_inline; + ce->key_direction = o->key_direction; + + ce->tls_crypt_file = o->tls_crypt_file; + ce->tls_crypt_inline = o->tls_crypt_inline; + } + + /* pre-cache tls-auth/crypt key file if persist-key was specified and keys + * were not already embedded in the config file + */ + if (o->persist_key) + { + if (ce->tls_auth_file && !ce->tls_auth_file_inline) + { + struct buffer in = buffer_read_from_file(o->tls_auth_file, &o->gc); + if (!buf_valid(&in)) + msg(M_FATAL, "Cannot pre-load tls-auth keyfile (%s)", + o->tls_auth_file); + + ce->tls_auth_file = INLINE_FILE_TAG; + ce->tls_auth_file_inline = (char *)in.data; + } + + if (ce->tls_crypt_file && !ce->tls_crypt_inline) + { + struct buffer in = buffer_read_from_file(o->tls_crypt_file, &o->gc); + if (!buf_valid(&in)) + msg(M_FATAL, "Cannot pre-load tls-crypt keyfile (%s)", + o->tls_auth_file); + + ce->tls_crypt_file = INLINE_FILE_TAG; + ce->tls_crypt_inline = (char *)in.data; + } + } } #ifdef _WIN32 @@ -3020,32 +3065,6 @@ options_postprocess_mutate(struct options *o) options_postprocess_mutate_ce(o, o->connection_list->array[i]); } - /* pre-cache tls-auth/crypt key file if persist-key was specified */ - if (o->persist_key) - { - if (o->tls_auth_file && !o->tls_auth_file_inline) - { - struct buffer in = buffer_read_from_file(o->tls_auth_file, &o->gc); - if (!buf_valid(&in)) - msg(M_FATAL, "Cannot pre-load tls-auth keyfile (%s)", - o->tls_auth_file); - - o->tls_auth_file = INLINE_FILE_TAG; - o->tls_auth_file_inline = (char *)in.data; - } - - if (o->tls_crypt_file && !o->tls_crypt_inline) - { - struct buffer in = buffer_read_from_file(o->tls_crypt_file, &o->gc); - if (!buf_valid(&in)) - msg(M_FATAL, "Cannot pre-load tls-crypt keyfile (%s)", - o->tls_auth_file); - - o->tls_crypt_file = INLINE_FILE_TAG; - o->tls_crypt_inline = (char *)in.data; - } - } - if (o->tls_server) { /* Check that DH file is specified, or explicitly disabled */ @@ -3312,12 +3331,22 @@ options_postprocess_filechecks(struct options *options) options->crl_file, R_OK, "--crl-verify"); } - errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, - options->tls_auth_file, R_OK, "--tls-auth"); - errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, - options->tls_crypt_file, R_OK, "--tls-crypt"); + ASSERT(options->connection_list); + for (int i = 0; i < options->connection_list->len; ++i) + { + struct connection_entry *ce = options->connection_list->array[i]; + + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + ce->tls_auth_file, R_OK, "--tls-auth"); + + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + ce->tls_crypt_file, R_OK, "--tls-crypt"); + + } + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, options->shared_secret_file, R_OK, "--secret"); + errs |= check_file_access(CHKACC_DIRPATH|CHKACC_FILEXSTWR, options->packet_id_file, R_OK|W_OK, "--replay-persist"); @@ -3674,7 +3703,7 @@ options_string(const struct options *o, { if (TLS_CLIENT || TLS_SERVER) { - if (o->tls_auth_file) + if (o->ce.tls_auth_file) { buf_printf(&out, ",tls-auth"); } @@ -7447,10 +7476,19 @@ add_option(struct options *options, { int key_direction; + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + key_direction = ascii2keydirection(msglevel, p[1]); if (key_direction >= 0) { - options->key_direction = key_direction; + if (permission_mask & OPT_P_GENERAL) + { + options->key_direction = key_direction; + } + else if (permission_mask & OPT_P_CONNECTION) + { + options->ce.key_direction = key_direction; + } } else { @@ -8019,35 +8057,66 @@ add_option(struct options *options, } else if (streq(p[0], "tls-auth") && p[1] && !p[3]) { - VERIFY_PERMISSION(OPT_P_GENERAL); - if (streq(p[1], INLINE_FILE_TAG) && p[2]) + int key_direction = -1; + + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + + if (permission_mask & OPT_P_GENERAL) { - options->tls_auth_file_inline = p[2]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->tls_auth_file_inline = p[2]; + } + else if (p[2]) + { + key_direction = ascii2keydirection(msglevel, p[2]); + if (key_direction < 0) + { + goto err; + } + options->key_direction = key_direction; + } + options->tls_auth_file = p[1]; } - else if (p[2]) + else if (permission_mask & OPT_P_CONNECTION) { - int key_direction; - - key_direction = ascii2keydirection(msglevel, p[2]); - if (key_direction >= 0) + options->ce.key_direction = KEY_DIRECTION_BIDIRECTIONAL; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) { - options->key_direction = key_direction; + options->ce.tls_auth_file_inline = p[2]; } - else + else if (p[2]) { - goto err; + key_direction = ascii2keydirection(msglevel, p[2]); + if (key_direction < 0) + { + goto err; + } + options->ce.key_direction = key_direction; } + options->ce.tls_auth_file = p[1]; } - options->tls_auth_file = p[1]; } else if (streq(p[0], "tls-crypt") && p[1] && !p[3]) { - VERIFY_PERMISSION(OPT_P_GENERAL); - if (streq(p[1], INLINE_FILE_TAG) && p[2]) + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + if (permission_mask & OPT_P_GENERAL) { - options->tls_crypt_inline = p[2]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->tls_crypt_inline = p[2]; + } + options->tls_crypt_file = p[1]; + } + else if (permission_mask & OPT_P_CONNECTION) + { + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->ce.tls_crypt_inline = p[2]; + } + options->ce.tls_crypt_file = p[1]; + } - options->tls_crypt_file = p[1]; } else if (streq(p[0], "key-method") && p[1] && !p[2]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 3a6c33f83..acbd1087a 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -130,6 +130,15 @@ struct connection_entry #define CE_MAN_QUERY_REMOTE_MASK (0x07) #define CE_MAN_QUERY_REMOTE_SHIFT (2) unsigned int flags; + + /* Shared secret used for TLS control channel authentication */ + const char *tls_auth_file; + const char *tls_auth_file_inline; + int key_direction; + + /* Shared secret used for TLS control channel authenticated encryption */ + const char *tls_crypt_file; + const char *tls_crypt_inline; }; struct remote_entry -- 2.47.2