compatibility with older versions. See the manual page on the
``--compat-mode`` for details.
+- The ``client-pending-auth`` management command now requires also the
+ key id. The management version has been changed to 5 to indicate this change.
+
Common errors with OpenSSL 3.0 and OpenVPN 2.6
----------------------------------------------
Both OpenVPN 2.6 and OpenSSL 3.0 tighten the security considerable, so some
Instruct OpenVPN server to send AUTH_PENDING and INFO_PRE message
to signal a pending authenticating to the client. A pending auth means
-that the connecting requires extra authentication like a one time
+that connecting requires extra authentication like a one time
password or doing a single sign on via web.
- client-pending-auth {CID} {EXTRA} {TIMEOUT}
+ client-pending-auth {CID} {KID} {EXTRA} {TIMEOUT}
The server will send AUTH_PENDING and INFO_PRE,{EXTRA} to the client. If the
client supports accepting keywords to AUTH_PENDING (announced via IV_PROTO),
For the format of {EXTRA} see below. For OpenVPN server this is a stateless
operation and needs to be followed by a client-deny/client-auth[-nt] command
-(that is the result of the out of band authentication).
+(that is the result of the out-of-band authentication).
+
+Note that the {KID} argument has been added in management version 5
+to specify the pending client key the authentication belongs to.
+This ensures that the pending auth message is tied strictly to the
+authentication session.
Before issuing a client-pending-auth to a client instead of a
client-auth/client-deny, the server should check the IV_SSO
-environment variable for whether the method is supported. Currently
+environment variable for whether the method is supported. Currently,
defined methods are crtext for challenge/response using text
(e.g., TOTP), openurl (deprecated) and webauth for opening a URL in
the client to continue authentication. A client supporting webauth and
}
bool
-send_control_channel_string_dowork(struct tls_multi *multi,
+send_control_channel_string_dowork(struct tls_session *session,
const char *str, int msglevel)
{
struct gc_arena gc = gc_new();
bool stat;
- ASSERT(multi);
- struct key_state *ks = get_key_scan(multi, 0);
+ ASSERT(session);
+ struct key_state *ks = &session->key[KS_PRIMARY];
/* buffered cleartext write onto TLS control channel */
stat = tls_send_payload(ks, (uint8_t *) str, strlen(str) + 1);
msg(msglevel, "SENT CONTROL [%s]: '%s' (status=%d)",
- tls_common_name(multi, false),
+ session->common_name ? session->common_name : "UNDEF",
sanitize_control_message(str, &gc),
(int) stat);
{
if (c->c2.tls_multi)
{
- bool ret = send_control_channel_string_dowork(c->c2.tls_multi,
- str, msglevel);
+ struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
+ bool ret = send_control_channel_string_dowork(session, str, msglevel);
reschedule_multi_process(c);
return ret;
/*
* Send a string to remote over the TLS control channel.
- * Used for push/pull messages, passing username/password,
- * etc.
+ * Used for push/pull messages, auth pending and other clear text
+ * control messages.
*
* This variant does not schedule the actual sending of the message
* The caller needs to ensure that it is scheduled or call
* send_control_channel_string
*
- * @param multi - The tls_multi structure of the VPN tunnel associated
- * with the packet.
+ * @param session - The session structure of the VPN tunnel associated
+ * with the packet. The method will always use the
+ * primary key (KS_PRIMARY) for sending the message
* @param str - The message to be sent
* @param msglevel - Message level to use for logging
*/
bool
-send_control_channel_string_dowork(struct tls_multi *multi,
+send_control_channel_string_dowork(struct tls_session *session,
const char *str, int msglevel);
*
* @param man The management interface struct
* @param cid_str The CID in string form
+ * @param kid_str The key ID in string form
* @param extra The string to be send to the client containing
* the information of the additional steps
*/
static void
man_client_pending_auth(struct management *man, const char *cid_str,
- const char *extra, const char *timeout_str)
+ const char *kid_str, const char *extra,
+ const char *timeout_str)
{
unsigned long cid = 0;
+ unsigned int kid = 0;
unsigned int timeout = 0;
- if (parse_cid(cid_str, &cid)
+ if (parse_cid(cid_str, &cid) && parse_uint(kid_str, "KID", &kid)
&& parse_uint(timeout_str, "TIMEOUT", &timeout))
{
if (man->persist.callback.client_pending_auth)
{
bool ret = (*man->persist.callback.client_pending_auth)
- (man->persist.callback.arg, cid, extra, timeout);
+ (man->persist.callback.arg, cid, kid, extra, timeout);
if (ret)
{
}
else if (streq(p[0], "client-pending-auth"))
{
- if (man_need(man, p, 3, 0))
+ if (man_need(man, p, 4, 0))
{
- man_client_pending_auth(man, p[1], p[2], p[3]);
+ man_client_pending_auth(man, p[1], p[2], p[3], p[4]);
}
}
else if (streq(p[0], "rsa-sig"))
#include "socket.h"
#include "mroute.h"
-#define MANAGEMENT_VERSION 4
+#define MANAGEMENT_VERSION 5
#define MANAGEMENT_N_PASSWORD_RETRIES 3
#define MANAGEMENT_LOG_HISTORY_INITIAL_SIZE 100
#define MANAGEMENT_ECHO_BUFFER_SIZE 100
struct buffer_list *cc_config); /* ownership transferred */
bool (*client_pending_auth) (void *arg,
const unsigned long cid,
+ const unsigned int kid,
const char *extra,
unsigned int timeout);
char *(*get_peer_info) (void *arg, const unsigned long cid);
static bool
management_client_pending_auth(void *arg,
const unsigned long cid,
+ const unsigned int mda_key_id,
const char *extra,
unsigned int timeout)
{
struct multi_context *m = (struct multi_context *) arg;
struct multi_instance *mi = lookup_by_cid(m, cid);
+
if (mi)
{
+ struct tls_multi *multi = mi->context.c2.tls_multi;
+ struct tls_session *session;
+
+ if (multi->session[TM_INITIAL].key[KS_PRIMARY].mda_key_id == mda_key_id)
+ {
+ session = &multi->session[TM_INITIAL];
+ }
+ else if (multi->session[TM_ACTIVE].key[KS_PRIMARY].mda_key_id == mda_key_id)
+ {
+ session = &multi->session[TM_ACTIVE];
+ }
+ else
+ {
+ return false;
+ }
+
/* sends INFO_PRE and AUTH_PENDING messages to client */
- bool ret = send_auth_pending_messages(mi->context.c2.tls_multi, extra,
+ bool ret = send_auth_pending_messages(multi, session, extra,
timeout);
reschedule_multi_process(&mi->context);
multi_schedule_context_wakeup(m, mi);
{
buf_printf(&buf, ",%s", client_reason);
}
- send_control_channel_string(c, BSTR(&buf), D_PUSH);
+
+ /* We kill the whole session, send the AUTH_FAILED to any TLS session
+ * that might be active */
+ send_control_channel_string_dowork(&c->c2.tls_multi->session[TM_INITIAL],
+ BSTR(&buf), D_PUSH);
+ send_control_channel_string_dowork(&c->c2.tls_multi->session[TM_ACTIVE],
+ BSTR(&buf), D_PUSH);
+
+ reschedule_multi_process(c);
+
}
gc_free(&gc);
bool
-send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra,
- unsigned int timeout)
+send_auth_pending_messages(struct tls_multi *tls_multi,
+ struct tls_session *session,
+ const char *extra, unsigned int timeout)
{
- struct key_state *ks = get_key_scan(tls_multi, 0);
+ struct key_state *ks = &session->key[KS_PRIMARY];
static const char info_pre[] = "INFO_PRE,";
struct gc_arena gc = gc_new();
if ((proto & IV_PROTO_AUTH_PENDING_KW) == 0)
{
- send_control_channel_string_dowork(tls_multi, "AUTH_PENDING", D_PUSH);
+ send_control_channel_string_dowork(session, "AUTH_PENDING", D_PUSH);
}
else
{
struct buffer buf = alloc_buf_gc(len, &gc);
buf_printf(&buf, auth_pre);
buf_printf(&buf, "%u", timeout);
- send_control_channel_string_dowork(tls_multi, BSTR(&buf), D_PUSH);
+ send_control_channel_string_dowork(session, BSTR(&buf), D_PUSH);
}
size_t len = strlen(extra) + 1 + sizeof(info_pre);
struct buffer buf = alloc_buf_gc(len, &gc);
buf_printf(&buf, info_pre);
buf_printf(&buf, "%s", extra);
- send_control_channel_string_dowork(tls_multi, BSTR(&buf), D_PUSH);
+ send_control_channel_string_dowork(session, BSTR(&buf), D_PUSH);
ks->auth_deferred_expire = now + timeout;
{
struct gc_arena gc = gc_new();
struct push_list push_list = { 0 };
+ struct tls_session *session = &multi->session[TM_ACTIVE];
prepare_auth_token_push_reply(multi, &gc, &push_list);
/* Construct a mimimal control channel push reply message */
struct buffer buf = alloc_buf_gc(PUSH_BUNDLE_SIZE, &gc);
buf_printf(&buf, "%s,%s", push_reply_cmd, e->option);
- send_control_channel_string_dowork(multi, BSTR(&buf), D_PUSH);
+ send_control_channel_string_dowork(session, BSTR(&buf), D_PUSH);
gc_free(&gc);
}
* more details on message format
*/
bool
-send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra,
+send_auth_pending_messages(struct tls_multi *tls_multi,
+ struct tls_session *session, const char *extra,
unsigned int timeout);
void send_restart(struct context *c, const char *kill_msg);
/**
* Sends a push reply message only containin the auth-token to update
- * the auth-token on the client
+ * the auth-token on the client. Always pushes to the active session
*
- * @param multi - The tls_multi structure belonging to the instance to push to
+ * @param multi - The \c tls_multi structure belonging to the instance
+ * to push to
*/
void send_push_reply_auth_token(struct tls_multi *multi);
*/
static bool
key_state_check_auth_pending_file(struct auth_deferred_status *ads,
- struct tls_multi *multi)
+ struct tls_multi *multi,
+ struct tls_session *session)
{
bool ret = true;
if (ads->auth_pending_file)
}
else
{
- send_auth_pending_messages(multi, BSTR(extra_buf), timeout);
+ send_auth_pending_messages(multi, session, BSTR(extra_buf), timeout);
}
}
/* Check if we the plugin has written the pending auth control
* file and send the pending auth to the client */
if (!key_state_check_auth_pending_file(&ks->script_auth,
- multi))
+ multi, session))
{
retval = OPENVPN_PLUGIN_FUNC_ERROR;
key_state_rm_auth_control_files(&ks->script_auth);
{
/* Check if the plugin has written the pending auth control
* file and send the pending auth to the client */
- if (!key_state_check_auth_pending_file(&ks->plugin_auth, multi))
+ if (!key_state_check_auth_pending_file(&ks->plugin_auth, multi, session))
{
retval = OPENVPN_PLUGIN_FUNC_ERROR;
}