This order the states from unauthenticated to authenticated and also
changes the comparison for KS_AUTH_FALSE from != to >
It also add comments and documents part using the state machine
better.
Remove a now obsolete comment and two obsolete ifdefs. While
keeping the ifdef in ssl_verify would save a few bytes of code,
this is too minor to justify keeping the ifdef
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Antonio Quartulli <antonio@openvpn.net>
Message-Id: <
20200709101603.11941-2-arne@rfc2549.org>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg20258.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
if (!IS_SIG(&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT(&mi->context))))
{
#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
- bool was_authenticated = false;
+ bool was_unauthenticated = true;
struct key_state *ks = NULL;
if (mi->context.c2.tls_multi)
{
ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY];
- was_authenticated = ks->authenticated;
+ was_unauthenticated = (ks->authenticated == KS_AUTH_FALSE);
}
#endif
pre_select(&mi->context);
#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
- if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated)
+ /*
+ * if we see the state transition from unauthenticated to deferred
+ * and an auth_control_file, we assume it got just added and add
+ * inotify watch to that file
+ */
+ if (ks && ks->auth_control_file && was_unauthenticated
+ && (ks->authenticated == KS_AUTH_DEFERRED))
{
/* watch acf file */
long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT);
if (session->opt->server && !(session->opt->ncp_enabled
&& session->opt->mode == MODE_SERVER && ks->key_id <= 0))
{
- if (ks->authenticated != KS_AUTH_FALSE)
+ if (ks->authenticated > KS_AUTH_FALSE)
{
if (!tls_session_generate_data_channel_keys(session))
{
secure_memzero(up, sizeof(*up));
/* Perform final authentication checks */
- if (ks->authenticated != KS_AUTH_FALSE)
+ if (ks->authenticated > KS_AUTH_FALSE)
{
verify_final_auth_checks(multi, session);
}
* Call OPENVPN_PLUGIN_TLS_FINAL plugin if defined, for final
* veto opportunity over authentication decision.
*/
- if ((ks->authenticated != KS_AUTH_FALSE)
+ if ((ks->authenticated > KS_AUTH_FALSE)
&& plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
{
key_state_export_keying_material(&ks->ks_ssl, session);
return true;
error:
+ ks->authenticated = KS_AUTH_FALSE;
secure_memzero(ks->key_src, sizeof(*ks->key_src));
if (up)
{
struct key_source server; /**< Random provided by server. */
};
+
+/**
+ * This reflects the (server side) authentication state after the TLS
+ * session has been established and key_method_2_read is called. If async auth
+ * is enabled the state will first move to KS_AUTH_DEFERRED before eventually
+ * being set to KS_AUTH_TRUE or KS_AUTH_FALSE
+ * Only KS_AUTH_TRUE is fully authenticated
+ */
enum ks_auth_state {
- KS_AUTH_FALSE,
- KS_AUTH_TRUE,
- KS_AUTH_DEFERRED
+ KS_AUTH_FALSE, /**< Key state is not authenticated */
+ KS_AUTH_DEFERRED, /**< Key state authentication is being deferred,
+ * by async auth */
+ KS_AUTH_TRUE /**< Key state is authenticated. TLS and user/pass
+ * succeeded. This includes AUTH_PENDING/OOB
+ * authentication as those hold the
+ * connection artificially in KS_AUTH_DEFERRED
+ */
};
/**
enum ks_auth_state authenticated;
time_t auth_deferred_expire;
-#ifdef ENABLE_DEF_AUTH
- /* If auth_deferred is true, authentication is being deferred */
#ifdef MANAGEMENT_DEF_AUTH
unsigned int mda_key_id;
unsigned int mda_status;
time_t acf_last_mod;
char *auth_control_file;
#endif
-#endif
};
/** Control channel wrapping (--tls-auth/--tls-crypt) context */
if (DECRYPT_KEY_ENABLED(multi, ks))
{
active = true;
- if (ks->authenticated != KS_AUTH_FALSE)
+ if (ks->authenticated > KS_AUTH_FALSE)
{
#ifdef ENABLE_DEF_AUTH
unsigned int s1 = ACF_DISABLED;
/*
* Main username/password verification entry point
+ *
+ * Will set session->ks[KS_PRIMARY].authenticated according to
+ * result of the username/password verification
*/
void
verify_user_pass(struct user_pass *up, struct tls_multi *multi,
*/
send_push_reply_auth_token(multi);
}
-#ifdef ENABLE_DEF_AUTH
msg(D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
(ks->authenticated == KS_AUTH_DEFERRED) ? "deferred" : "succeeded",
up->username,
(session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
-#else
- msg(D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
- "succeeded",
- up->username,
- (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
-#endif
}
else
{
}
/* Don't allow the CN to change once it's been locked */
- if (ks->authenticated != KS_AUTH_FALSE && multi->locked_cn)
+ if (ks->authenticated > KS_AUTH_FALSE && multi->locked_cn)
{
const char *cn = session->common_name;
if (cn && strcmp(cn, multi->locked_cn))
}
/* Don't allow the cert hashes to change once they have been locked */
- if (ks->authenticated != KS_AUTH_FALSE && multi->locked_cert_hash_set)
+ if (ks->authenticated > KS_AUTH_FALSE && multi->locked_cert_hash_set)
{
const struct cert_hash_set *chs = session->cert_hash_set;
if (chs && !cert_hash_compare(chs, multi->locked_cert_hash_set))
}
/* verify --client-config-dir based authentication */
- if (ks->authenticated != KS_AUTH_FALSE && session->opt->client_config_dir_exclusive)
+ if (ks->authenticated > KS_AUTH_FALSE && session->opt->client_config_dir_exclusive)
{
struct gc_arena gc = gc_new();