@@ -49,6 +49,12 @@
- IV constructed with XOR instead of concatenation to not have (parts) of
the real IV on the wire
+Allow overriding username with ``--override-username``
+ This is intended to allow using auth-gen-token in scenarios where the
+ clients use certificates and multi-factor authentication. This will
+ also generate a 'push "auth-token-user newusername"' directives in
+ push replies.
+
Deprecated features
-------------------
``secret`` support has been removed by default.
@@ -89,6 +89,12 @@
will lead to authentication bypass (as does returning success on a wrong
password from a script).
+ **Note:** the username for ``--auth-gen-token`` can be overridden by
+ ``--override-user``. In this case the client will be pushed also the
+ ``--auth-token-user`` option and an auth token that is valid for that
+ username instead of the original username that the client authenticated
+ with.
+
--auth-gen-token-secret file
Specifies a file that holds a secret for the HMAC used in
``--auth-gen-token`` If ``file`` is not present OpenVPN will generate a
@@ -412,6 +418,32 @@
This option requires that ``--disable-occ`` NOT be used.
+--override-username
+ Sets the username of a connection to the specified username. This username
+ will also be used by ``--auth-gen-token``. However, the overridden
+ username comes only into effect *after* the ``--client-config-dir`` has been
+ read and the ``--auth-user-pass-verify`` and ``--client-connect`` scripts
+ have been run.
+
+ Also ``username-as-common-name`` will use the client provided username
+ as common-name. It is recommended to avoid the use of the
+ ``--override-username`` option if the option ``--username-as-common-name``
+ is being used.
+
+ The changed username will be picked up by the status output and also by
+ the ``--auth-gen-token`` option. It will also be pushed to the client
+ using ``--auth-token-user``.
+
+ Special care should be taken that both the initial username of the client
+ and the overridden username are handled correctly when using
+ ``--override-username`` and the related options to avoid
+ authentication/authorisation bypasses.
+
+ This option is mainly intended for use cases that use certificates and
+ multi factor authentication and therefore do not provide a username that
+ can be used for ``--auth-gen-token`` to allow providing a username in
+ these scenarios.
+
--port-share args
Share OpenVPN TCP with another service
@@ -42,7 +42,9 @@
#include "ssl_verify.h"
#include "ssl_ncp.h"
#include "vlan.h"
+#include "auth_token.h"
#include <inttypes.h>
+#include <string.h>
#include "memdbg.h"
@@ -2675,6 +2677,50 @@
NULL,
};
+/**
+ * Overrides the locked username with the username of --override-username
+ * @param mi the multi instance that should be modified.
+ */
+static void
+override_locked_username(struct multi_instance *mi)
+{
+ struct tls_multi *multi = mi->context.c2.tls_multi;
+ struct options *options = &mi->context.options;
+ struct tls_session *session = &multi->session[TM_ACTIVE];
+
+ if (!multi->locked_original_username
+ && strcmp(multi->locked_username, options->override_username) != 0)
+ {
+ multi->locked_original_username = multi->locked_username;
+ multi->locked_username = strdup(options->override_username);
+
+ /* Override also the common name if username should be set as common
+ * name */
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
+ {
+ set_common_name(session, multi->locked_username);
+ free(multi->locked_cn);
+ multi->locked_cn = NULL;
+ tls_lock_common_name(multi);
+ }
+
+ /* Regenerate the auth-token if enabled */
+ if (multi->auth_token_initial)
+ {
+ struct user_pass up;
+ CLEAR(up);
+ strncpynt(up.username, multi->locked_username,
+ sizeof(up.username));
+
+ generate_auth_token(&up, multi);
+ }
+
+ msg(D_MULTI_LOW, "MULTI: Note, override-username changes username "
+ "from '%s' to '%s'",
+ multi->locked_original_username,
+ multi->locked_username);
+ }
+}
/*
* Called as soon as the SSL/TLS connection is authenticated.
*
@@ -2778,6 +2824,11 @@
(*cur_handler_index)++;
}
+ if (mi->context.options.override_username)
+ {
+ override_locked_username(mi);
+ }
+
/* Check if we have forbidding options in the current mode */
if (dco_enabled(&mi->context.options)
&& !dco_check_option(D_MULTI_ERRORS, &mi->context.options))
@@ -452,6 +452,8 @@
" Only valid in a client-specific config file.\n"
"--disable : Client is disabled.\n"
" Only valid in a client-specific config file.\n"
+ "--override-username: Overrides the client-specific username to be used.\n"
+ " Only valid in a client-specific config file.\n"
"--verify-client-cert [none|optional|require] : perform no, optional or\n"
" mandatory client certificate verification.\n"
" Default is to require the client to supply a certificate.\n"
@@ -7955,6 +7957,23 @@
VERIFY_PERMISSION(OPT_P_INSTANCE);
options->disable = true;
}
+ else if (streq(p[0], "override-username") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION(OPT_P_INSTANCE);
+ if (strlen(p[1]) > TLS_USERNAME_LEN)
+ {
+ msg(msglevel, "override-username exceeds the maximum length of %d "
+ "characters", TLS_USERNAME_LEN);
+
+ /* disable the connection since ignoring the request to
+ * set another username might cause serious problems */
+ options->disable = true;
+ }
+ else
+ {
+ options->override_username = p[1];
+ }
+ }
else if (streq(p[0], "tcp-nodelay") && !p[1])
{
VERIFY_PERMISSION(OPT_P_GENERAL);
@@ -504,6 +504,7 @@
const char *client_config_dir;
bool ccd_exclusive;
bool disable;
+ const char *override_username;
int n_bcast_buf;
int tcp_queue_limit;
struct iroute *iroutes;
@@ -595,9 +595,19 @@
*/
if (tls_multi->auth_token)
{
- push_option_fmt(gc, push_list, M_USAGE,
- "auth-token %s",
+ push_option_fmt(gc, push_list, M_USAGE, "auth-token %s",
tls_multi->auth_token);
+
+ char *base64user = NULL;
+ int ret = openvpn_base64_encode(tls_multi->locked_username,
+ (int)strlen(tls_multi->locked_username),
+ &base64user);
+ if (ret < USER_PASS_LEN && ret > 0)
+ {
+ push_option_fmt(gc, push_list, M_USAGE, "auth-token-user %s",
+ base64user);
+ }
+ free(base64user);
}
}
@@ -1262,6 +1262,7 @@
free(multi->peer_info);
free(multi->locked_cn);
free(multi->locked_username);
+ free(multi->locked_original_username);
cert_hash_free(multi->locked_cert_hash_set);
@@ -628,7 +628,16 @@
* Our locked common name, username, and cert hashes (cannot change during the life of this tls_multi object)
*/
char *locked_cn;
+
+ /** The locked username is the username we assume the client is using.
+ * Normally the username used for initial authentication unless
+ * overridden by --override-username */
char *locked_username;
+
+ /** The username that client initially used before being overridden
+ * by --override-user */
+ char *locked_original_username;
+
struct cert_hash_set *locked_cert_hash_set;
/** Time of last when we updated the cached state of
@@ -48,9 +48,6 @@
#include "push.h"
#include "ssl_util.h"
-/** Maximum length of common name */
-#define TLS_USERNAME_LEN 64
-
static void
string_mod_remap_name(char *str)
{
@@ -85,10 +82,7 @@
}
}
-/*
- * Set the given session's common_name
- */
-static void
+void
set_common_name(struct tls_session *session, const char *common_name)
{
if (session->common_name)
@@ -153,7 +147,10 @@
{
if (multi->locked_username)
{
- if (strcmp(username, multi->locked_username) != 0)
+ /* If the username has been overridden, we accept both the original
+ * username and the changed username */
+ if (strcmp(username, multi->locked_username) != 0
+ && (!multi->locked_original_username || strcmp(username, multi->locked_original_username) != 0))
{
msg(D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled",
multi->locked_username,
@@ -1613,6 +1610,17 @@
*/
bool skip_auth = false;
+ /* Replace username early if override-username is in effect but only
+ * if client is sending the original username */
+ if (multi->locked_original_username
+ && strncmp(up->username, multi->locked_original_username, sizeof(up->username)) == 0)
+ {
+ msg(D_MULTI_LOW, "TLS: Replacing client provided username '%s' with "
+ "username from override-user '%s'", up->username,
+ multi->locked_username);
+ strncpy(up->username, multi->locked_username, sizeof(up->username));
+ }
+
/*
* If server is configured with --auth-gen-token and the client sends
* something that looks like an authentication token, this
@@ -51,6 +51,9 @@
/** Maximum certificate depth we will allow */
#define MAX_CERT_DEPTH 16
+/** Maximum length of common name */
+#define TLS_USERNAME_LEN 64
+
/** Structure containing the hash for a single certificate */
struct cert_hash {
unsigned char sha256_hash[256/8];
@@ -146,6 +149,16 @@
*/
const char *tls_common_name(const struct tls_multi *multi, const bool null);
+
+/**
+ * Sets the common name field for the given tunnel
+ *
+ * @param multi The tunnel to set the common name for
+ * @param common_name The name to set the common name to
+ */
+void
+set_common_name(struct tls_session *session, const char *common_name);
+
/**
* Returns the username field for the given tunnel
*