diff options
-rw-r--r-- | doc/man-sections/client-options.rst | 7 | ||||
-rw-r--r-- | src/openvpn/crypto.h | 5 | ||||
-rw-r--r-- | src/openvpn/forward.c | 4 | ||||
-rw-r--r-- | src/openvpn/multi.c | 7 | ||||
-rw-r--r-- | src/openvpn/options.c | 30 | ||||
-rw-r--r-- | src/openvpn/options.h | 2 | ||||
-rw-r--r-- | src/openvpn/push.c | 37 | ||||
-rw-r--r-- | src/openvpn/push.h | 2 | ||||
-rw-r--r-- | src/openvpn/sig.c | 30 | ||||
-rw-r--r-- | src/openvpn/ssl.c | 5 | ||||
-rw-r--r-- | src/openvpn/ssl.h | 4 | ||||
-rw-r--r-- | src/openvpn/ssl_ncp.c | 5 |
12 files changed, 129 insertions, 9 deletions
diff --git a/doc/man-sections/client-options.rst b/doc/man-sections/client-options.rst index 8e0e4f1..5a90689 100644 --- a/doc/man-sections/client-options.rst +++ b/doc/man-sections/client-options.rst @@ -220,9 +220,14 @@ configuration. immediately close its client instance object rather than waiting for a timeout. + If both server and client support sending this message using the control + channel, the message will be sent as control-channel message. Otherwise + the message is sent as data-channel message, which will be ignored by + data-channel offloaded peers. + The **n** parameter (default :code:`1` if not present) controls the maximum number of attempts that the client will try to resend the exit - notification message. + notification message if messages are sent in data-channel mode. In UDP server mode, send :code:`RESTART` control channel command to connected clients. The ``n`` parameter (default :code:`1` if not present) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 98e2c76..5ea8890 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -264,6 +264,11 @@ struct crypto_options /**< Bit-flag indicating that we do not allow clients that do * not support resending the wrapped client key (WKc) with the * third packet of the three-way handshake */ +#define CO_USE_CC_EXIT_NOTIFY (1<<6) + /**< Bit-flag indicating that explicit exit notifies should be + * sent via the control channel instead of using an OCC message + */ + unsigned int flags; /**< Bit-flags determining behavior of * security operation functions. */ }; diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 468eeee..6a45b9e 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -260,6 +260,10 @@ check_incoming_control_channel(struct context *c) { receive_auth_pending(c, &buf); } + else if (buf_string_match_head_str(&buf, "EXIT")) + { + receive_exit_message(c); + } else { msg(D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR(&buf)); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 1bbeab7..b9b087e 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1801,10 +1801,15 @@ multi_client_set_protocol_options(struct context *c) #ifdef HAVE_EXPORT_KEYING_MATERIAL if (proto & IV_PROTO_TLS_KEY_EXPORT) { - o->data_channel_crypto_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; + o->imported_protocol_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; } #endif + if (proto & IV_PROTO_CC_EXIT_NOTIFY) + { + o->imported_protocol_flags |= CO_USE_CC_EXIT_NOTIFY; + } + /* Select cipher if client supports Negotiable Crypto Parameters */ /* if we have already created our key, we cannot *change* our own diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 45fbb63..e44993c 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3341,7 +3341,7 @@ pre_connect_restore(struct options *o, struct gc_arena *gc) o->push_continuation = 0; o->push_option_types_found = 0; - o->data_channel_crypto_flags = 0; + o->imported_protocol_flags = 0; } static void @@ -8496,11 +8496,13 @@ add_option(struct options *options, } else if (streq(p[0], "key-derivation") && p[1]) { + /* NCP only option that is pushed by the server to enable EKM, + * should not be used by normal users in config files*/ VERIFY_PERMISSION(OPT_P_NCP) #ifdef HAVE_EXPORT_KEYING_MATERIAL if (streq(p[1], "tls-ekm")) { - options->data_channel_crypto_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; + options->imported_protocol_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; } else #endif @@ -8508,6 +8510,30 @@ add_option(struct options *options, msg(msglevel, "Unknown key-derivation method %s", p[1]); } } + else if (streq(p[0], "protocol-flags") && p[1]) + { + /* NCP only option that is pushed by the server to enable protocol + * features that are negotiated, should not be used by normal users + * in config files */ + VERIFY_PERMISSION(OPT_P_NCP) + for (size_t j = 1; j < MAX_PARMS && p[j] != NULL; j++) + { + if (streq(p[j], "cc-exit")) + { + options->imported_protocol_flags |= CO_USE_CC_EXIT_NOTIFY; + } +#ifdef HAVE_EXPORT_KEYING_MATERIAL + else if (streq(p[j], "tls-ekm")) + { + options->imported_protocol_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; + } +#endif + else + { + msg(msglevel, "Unknown protocol-flags flag: %s", p[j]); + } + } + } else if (streq(p[0], "prng") && p[1] && !p[3]) { msg(M_WARN, "NOTICE: --prng option ignored (SSL library PRNG is used)"); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index b70cd42..f438cd2 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -681,7 +681,7 @@ struct options bool allow_recursive_routing; /* data channel crypto flags set by push/pull. Reuses the CO_* crypto_flags */ - unsigned int data_channel_crypto_flags; + unsigned int imported_protocol_flags; }; #define streq(x, y) (!strcmp((x), (y))) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 4cbc89e..47a7992 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -180,6 +180,21 @@ server_pushed_signal(struct context *c, const struct buffer *buffer, const bool } void +receive_exit_message(struct context *c) +{ + dmsg(D_STREAM_ERRORS, "Exit message received by peer"); + c->sig->signal_received = SIGTERM; + c->sig->signal_text = "remote-exit"; +#ifdef ENABLE_MANAGEMENT + if (management) + { + management_notify(management, "info", c->sig->signal_text, "EXIT"); + } +#endif +} + + +void server_pushed_info(struct context *c, const struct buffer *buffer, const int adv) { @@ -606,10 +621,30 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, { push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } - if (o->data_channel_crypto_flags & CO_USE_TLS_KEY_MATERIAL_EXPORT) + + struct buffer proto_flags = alloc_buf_gc(128, gc); + + if (o->imported_protocol_flags & CO_USE_CC_EXIT_NOTIFY) + { + buf_printf(&proto_flags, " cc-exit"); + + /* if the cc exit flag is supported, pushing tls-ekm via protocol-flags + * is also supported */ + if (o->imported_protocol_flags & CO_USE_TLS_KEY_MATERIAL_EXPORT) + { + buf_printf(&proto_flags, " tls-ekm"); + } + } + else if (o->imported_protocol_flags & CO_USE_TLS_KEY_MATERIAL_EXPORT) { push_option_fmt(gc, push_list, M_USAGE, "key-derivation tls-ekm"); } + + if (buf_len(&proto_flags) > 0) + { + push_option_fmt(gc, push_list, M_USAGE, "protocol-flags%s", buf_str(&proto_flags)); + } + return true; } diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 62fad4a..7138055 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -48,6 +48,8 @@ void receive_auth_failed(struct context *c, const struct buffer *buffer); void server_pushed_signal(struct context *c, const struct buffer *buffer, const bool restart, const int adv); +void receive_exit_message(struct context *c); + void server_pushed_info(struct context *c, const struct buffer *buffer, const int adv); diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index e06edd2..65cd25c 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -321,20 +321,46 @@ print_status(const struct context *c, struct status_output *so) gc_free(&gc); } + +/* Small helper function to determine if we should send the exit notification + * via control channel */ +static inline bool +cc_exit_notify_enabled(struct context *c) +{ + /* Check if we have TLS active at all */ + if (!c->c2.tls_multi) + { + return false; + } + + const struct key_state *ks = get_primary_key(c->c2.tls_multi); + return (ks->crypto_options.flags & CO_USE_CC_EXIT_NOTIFY); +} + /* * Handle the triggering and time-wait of explicit * exit notification. */ - static void process_explicit_exit_notification_init(struct context *c) { msg(M_INFO, "SIGTERM received, sending exit notification to peer"); + /* init the timeout to send the OCC_EXIT messages if cc exit is not + * enabled and also to exit after waiting for retries of resending of + * exit messages */ event_timeout_init(&c->c2.explicit_exit_notification_interval, 1, 0); reset_coarse_timers(c); + signal_reset(c->sig); halt_non_edge_triggered_signals(); c->c2.explicit_exit_notification_time_wait = now; + + /* Check if we are in TLS mode and should send the notification via data + * channel */ + if (cc_exit_notify_enabled(c)) + { + send_control_channel_string(c, "EXIT", D_PUSH); + } } void @@ -351,7 +377,7 @@ process_explicit_exit_notification_timer_wakeup(struct context *c) c->sig->signal_received = SIGTERM; c->sig->signal_text = "exit-with-notification"; } - else + else if (!cc_exit_notify_enabled(c)) { c->c2.occ_op = OCC_EXIT; } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 33e145b..d3f7a02 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1719,7 +1719,7 @@ tls_session_update_crypto_params(struct tls_multi *multi, } /* Import crypto settings that might be set by pull/push */ - session->opt->crypto_flags |= options->data_channel_crypto_flags; + session->opt->crypto_flags |= options->imported_protocol_flags; return tls_session_update_crypto_params_do_work(multi, session, options, frame, frame_fragment, lsi); @@ -1969,6 +1969,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session) /* support for the --dns option */ iv_proto |= IV_PROTO_DNS_OPTION; + /* support for exit notify via control channel */ + iv_proto |= IV_PROTO_CC_EXIT_NOTIFY; + /* support for receiving push_reply before sending * push request, also signal that the client wants * to get push-reply messages without without requiring a round diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 76b1b67..12ffd44 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -96,6 +96,10 @@ /** Supports the --dns option introduced in version 2.6 */ #define IV_PROTO_DNS_OPTION (1<<6) +/** Support for explicit exit notify via control channel + * This also includes support for the protocol-flags pushed option */ +#define IV_PROTO_CC_EXIT_NOTIFY (1<<7) + /* Default field in X509 to be username */ #define X509_USERNAME_FIELD_DEFAULT "CN" diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index a58ced5..fe84919 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -419,6 +419,11 @@ p2p_ncp_set_options(struct tls_multi *multi, struct tls_session *session) multi->peer_id = 0x76706e; /* 'v' 'p' 'n' */ } + if (iv_proto_peer & IV_PROTO_CC_EXIT_NOTIFY) + { + session->opt->crypto_flags |= CO_USE_CC_EXIT_NOTIFY; + } + #if defined(HAVE_EXPORT_KEYING_MATERIAL) if (iv_proto_peer & IV_PROTO_TLS_KEY_EXPORT) { |