summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ssl.c527
-rw-r--r--ssl.h91
-rw-r--r--ssl_common.h59
-rw-r--r--ssl_verify.c553
-rw-r--r--ssl_verify.h89
5 files changed, 713 insertions, 606 deletions
diff --git a/ssl.c b/ssl.c
index fbb0d02..ec524e7 100644
--- a/ssl.c
+++ b/ssl.c
@@ -1086,45 +1086,6 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
/** @} name Function for authenticating a new connection from a remote OpenVPN peer */
-
-static bool
-tls_lock_username (struct tls_multi *multi, const char *username)
-{
- if (multi->locked_username)
- {
- if (!username || strcmp (username, multi->locked_username))
- {
- msg (D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled",
- multi->locked_username,
- np(username));
-
- /* disable the tunnel */
- tls_deauthenticate (multi);
- return false;
- }
- }
- else
- {
- if (username)
- multi->locked_username = string_alloc (username, NULL);
- }
- return true;
-}
-
-const char *
-tls_username (const struct tls_multi *multi, const bool null)
-{
- const char *ret = NULL;
- if (multi)
- ret = multi->locked_username;
- if (ret && strlen (ret))
- return ret;
- else if (null)
- return NULL;
- else
- return "UNDEF";
-}
-
#ifdef ENABLE_X509_TRACK
void
@@ -1150,234 +1111,6 @@ x509_track_add (const struct x509_track **ll_head, const char *name, int msgleve
#endif
-#ifdef ENABLE_DEF_AUTH
-/* key_state_test_auth_control_file return values,
- NOTE: acf_merge indexing depends on these values */
-#define ACF_UNDEFINED 0
-#define ACF_SUCCEEDED 1
-#define ACF_DISABLED 2
-#define ACF_FAILED 3
-#endif
-
-#ifdef MANAGEMENT_DEF_AUTH
-static void
-man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason)
-{
- if (multi->client_reason)
- {
- free (multi->client_reason);
- multi->client_reason = NULL;
- }
- if (client_reason && strlen (client_reason))
- multi->client_reason = string_alloc (client_reason, NULL);
-}
-
-static inline unsigned int
-man_def_auth_test (const struct key_state *ks)
-{
- if (management_enable_def_auth (management))
- return ks->mda_status;
- else
- return ACF_DISABLED;
-}
-#endif
-
-#ifdef PLUGIN_DEF_AUTH
-
-/*
- * auth_control_file functions
- */
-
-static void
-key_state_rm_auth_control_file (struct key_state *ks)
-{
- if (ks && ks->auth_control_file)
- {
- delete_file (ks->auth_control_file);
- free (ks->auth_control_file);
- ks->auth_control_file = NULL;
- }
-}
-
-static void
-key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options *opt)
-{
- struct gc_arena gc = gc_new ();
- const char *acf;
-
- key_state_rm_auth_control_file (ks);
- acf = create_temp_file (opt->tmp_dir, "acf", &gc);
- if( acf ) {
- ks->auth_control_file = string_alloc (acf, NULL);
- setenv_str (opt->es, "auth_control_file", ks->auth_control_file);
- } /* FIXME: Should have better error handling? */
- gc_free (&gc);
-}
-
-static unsigned int
-key_state_test_auth_control_file (struct key_state *ks)
-{
- if (ks && ks->auth_control_file)
- {
- unsigned int ret = ks->auth_control_status;
- if (ret == ACF_UNDEFINED)
- {
- FILE *fp = fopen (ks->auth_control_file, "r");
- if (fp)
- {
- const int c = fgetc (fp);
- if (c == '1')
- ret = ACF_SUCCEEDED;
- else if (c == '0')
- ret = ACF_FAILED;
- fclose (fp);
- ks->auth_control_status = ret;
- }
- }
- return ret;
- }
- return ACF_DISABLED;
-}
-
-#endif
-
-/*
- * Return current session authentication state. Return
- * value is TLS_AUTHENTICATION_x.
- */
-
-int
-tls_authentication_status (struct tls_multi *multi, const int latency)
-{
- bool deferred = false;
- bool success = false;
- bool active = false;
-
-#ifdef ENABLE_DEF_AUTH
- static const unsigned char acf_merge[] =
- {
- ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_UNDEFINED */
- ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_SUCCEEDED */
- ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_DISABLED */
- ACF_FAILED, /* s1=ACF_UNDEFINED s2=ACF_FAILED */
- ACF_UNDEFINED, /* s1=ACF_SUCCEEDED s2=ACF_UNDEFINED */
- ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_SUCCEEDED */
- ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_DISABLED */
- ACF_FAILED, /* s1=ACF_SUCCEEDED s2=ACF_FAILED */
- ACF_UNDEFINED, /* s1=ACF_DISABLED s2=ACF_UNDEFINED */
- ACF_SUCCEEDED, /* s1=ACF_DISABLED s2=ACF_SUCCEEDED */
- ACF_DISABLED, /* s1=ACF_DISABLED s2=ACF_DISABLED */
- ACF_FAILED, /* s1=ACF_DISABLED s2=ACF_FAILED */
- ACF_FAILED, /* s1=ACF_FAILED s2=ACF_UNDEFINED */
- ACF_FAILED, /* s1=ACF_FAILED s2=ACF_SUCCEEDED */
- ACF_FAILED, /* s1=ACF_FAILED s2=ACF_DISABLED */
- ACF_FAILED /* s1=ACF_FAILED s2=ACF_FAILED */
- };
-#endif
-
- if (multi)
- {
- int i;
-
-#ifdef ENABLE_DEF_AUTH
- if (latency && multi->tas_last && multi->tas_last + latency >= now)
- return TLS_AUTHENTICATION_UNDEFINED;
- multi->tas_last = now;
-#endif
-
- for (i = 0; i < KEY_SCAN_SIZE; ++i)
- {
- struct key_state *ks = multi->key_scan[i];
- if (DECRYPT_KEY_ENABLED (multi, ks))
- {
- active = true;
- if (ks->authenticated)
- {
-#ifdef ENABLE_DEF_AUTH
- unsigned int s1 = ACF_DISABLED;
- unsigned int s2 = ACF_DISABLED;
-#ifdef PLUGIN_DEF_AUTH
- s1 = key_state_test_auth_control_file (ks);
-#endif
-#ifdef MANAGEMENT_DEF_AUTH
- s2 = man_def_auth_test (ks);
-#endif
- ASSERT (s1 < 4 && s2 < 4);
- switch (acf_merge[(s1<<2) + s2])
- {
- case ACF_SUCCEEDED:
- case ACF_DISABLED:
- success = true;
- ks->auth_deferred = false;
- break;
- case ACF_UNDEFINED:
- if (now < ks->auth_deferred_expire)
- deferred = true;
- break;
- case ACF_FAILED:
- ks->authenticated = false;
- break;
- default:
- ASSERT (0);
- }
-#else
- success = true;
-#endif
- }
- }
- }
- }
-
-#if 0
- dmsg (D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred);
-#endif
-
- if (success)
- return TLS_AUTHENTICATION_SUCCEEDED;
- else if (!active || deferred)
- return TLS_AUTHENTICATION_DEFERRED;
- else
- return TLS_AUTHENTICATION_FAILED;
-}
-
-#ifdef MANAGEMENT_DEF_AUTH
-/*
- * For deferred auth, this is where the management interface calls (on server)
- * to indicate auth failure/success.
- */
-bool
-tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason)
-{
- bool ret = false;
- if (multi)
- {
- int i;
- man_def_auth_set_client_reason (multi, client_reason);
- for (i = 0; i < KEY_SCAN_SIZE; ++i)
- {
- struct key_state *ks = multi->key_scan[i];
- if (ks->mda_key_id == mda_key_id)
- {
- ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED;
- ret = true;
- }
- }
- }
- return ret;
-}
-#endif
-
-void
-tls_deauthenticate (struct tls_multi *multi)
-{
- if (multi)
- {
- int i, j;
- for (i = 0; i < TM_SIZE; ++i)
- for (j = 0; j < KS_SIZE; ++j)
- multi->session[i].key[j].authenticated = false;
- }
-}
/*
* Initialize SSL context.
@@ -2659,173 +2392,6 @@ read_string_discard (struct buffer *buf)
}
/*
- * Authenticate a client using username/password.
- * Runs on server.
- *
- * If you want to add new authentication methods,
- * this is the place to start.
- */
-
-static bool
-verify_user_pass_script (struct tls_session *session, const struct user_pass *up)
-{
- struct gc_arena gc = gc_new ();
- struct argv argv = argv_new ();
- const char *tmp_file = "";
- bool ret = false;
-
- /* Is username defined? */
- if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
- {
- /* Set environmental variables prior to calling script */
- setenv_str (session->opt->es, "script_type", "user-pass-verify");
-
- if (session->opt->auth_user_pass_verify_script_via_file)
- {
- struct status_output *so;
-
- tmp_file = create_temp_file (session->opt->tmp_dir, "up", &gc);
- if( tmp_file ) {
- so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
- status_printf (so, "%s", up->username);
- status_printf (so, "%s", up->password);
- if (!status_close (so))
- {
- msg (D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s",
- tmp_file);
- goto done;
- }
- } else {
- msg (D_TLS_ERRORS, "TLS Auth Error: could not create write "
- "username/password to temp file");
- }
- }
- else
- {
- setenv_str (session->opt->es, "username", up->username);
- setenv_str (session->opt->es, "password", up->password);
- }
-
- /* setenv incoming cert common name for script */
- setenv_str (session->opt->es, "common_name", session->common_name);
-
- /* setenv client real IP address */
- setenv_untrusted (session);
-
- /* format command line */
- argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
-
- /* call command */
- ret = openvpn_run_script (&argv, session->opt->es, 0,
- "--auth-user-pass-verify");
-
- if (!session->opt->auth_user_pass_verify_script_via_file)
- setenv_del (session->opt->es, "password");
- }
- else
- {
- msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username");
- }
-
- done:
- if (tmp_file && strlen (tmp_file) > 0)
- delete_file (tmp_file);
-
- argv_reset (&argv);
- gc_free (&gc);
- return ret;
-}
-
-static int
-verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
-{
- int retval = OPENVPN_PLUGIN_FUNC_ERROR;
- struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
-
- /* Is username defined? */
- if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
- {
- /* set username/password in private env space */
- setenv_str (session->opt->es, "username", raw_username);
- setenv_str (session->opt->es, "password", up->password);
-
- /* setenv incoming cert common name for script */
- setenv_str (session->opt->es, "common_name", session->common_name);
-
- /* setenv client real IP address */
- setenv_untrusted (session);
-
-#ifdef PLUGIN_DEF_AUTH
- /* generate filename for deferred auth control file */
- key_state_gen_auth_control_file (ks, session->opt);
-#endif
-
- /* call command */
- retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es, -1, NULL);
-
-#ifdef PLUGIN_DEF_AUTH
- /* purge auth control filename (and file itself) for non-deferred returns */
- if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
- key_state_rm_auth_control_file (ks);
-#endif
-
- setenv_del (session->opt->es, "password");
- setenv_str (session->opt->es, "username", up->username);
- }
- else
- {
- msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username");
- }
-
- return retval;
-}
-
-/*
- * MANAGEMENT_DEF_AUTH internal ssl.c status codes
- */
-#define KMDA_ERROR 0
-#define KMDA_SUCCESS 1
-#define KMDA_UNDEF 2
-#define KMDA_DEF 3
-
-#ifdef MANAGEMENT_DEF_AUTH
-static int
-verify_user_pass_management (struct tls_session *session, const struct user_pass *up, const char *raw_username)
-{
- int retval = KMDA_ERROR;
- struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
-
- /* Is username defined? */
- if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
- {
- /* set username/password in private env space */
- setenv_str (session->opt->es, "username", raw_username);
- setenv_str (session->opt->es, "password", up->password);
-
- /* setenv incoming cert common name for script */
- setenv_str (session->opt->es, "common_name", session->common_name);
-
- /* setenv client real IP address */
- setenv_untrusted (session);
-
- if (management)
- management_notify_client_needing_auth (management, ks->mda_key_id, session->opt->mda_context, session->opt->es);
-
- setenv_del (session->opt->es, "password");
- setenv_str (session->opt->es, "username", up->username);
-
- retval = KMDA_SUCCESS;
- }
- else
- {
- msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username");
- }
-
- return retval;
-}
-#endif
-
-/*
* Handle the reading and writing of key data to and from
* the TLS control channel (cleartext).
*/
@@ -3091,23 +2657,18 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
- struct gc_arena gc = gc_new ();
+
int key_method_flags;
- char *options;
- struct user_pass *up;
+ bool username_status, password_status;
- bool man_def_auth = KMDA_UNDEF;
+ struct gc_arena gc = gc_new ();
+ char *options;
-#ifdef MANAGEMENT_DEF_AUTH
- if (management_enable_def_auth (management))
- man_def_auth = KMDA_DEF;
-#endif
+ /* allocate temporary objects */
+ ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
ASSERT (session->opt->key_method == 2);
- /* allocate temporary objects */
- ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
-
/* discard leading uint32 */
ASSERT (buf_advance (buf, 4));
@@ -3135,21 +2696,17 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
goto error;
}
- /* should we check username/password? */
ks->authenticated = false;
- if (session->opt->auth_user_pass_verify_script
- || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
- || man_def_auth == KMDA_DEF)
+
+ if (verify_user_pass_enabled(session))
{
- int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
- bool s2 = true;
- char *raw_username;
- bool username_status, password_status;
+ /* Perform username/password authentication */
+ struct user_pass *up;
- /* get username/password from plaintext buffer */
ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
username_status = read_string (buf, up->username, USER_PASS_LEN);
password_status = read_string (buf, up->password, USER_PASS_LEN);
+
if (!username_status || !password_status)
{
CLEAR (*up);
@@ -3160,76 +2717,18 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
}
}
- /* preserve raw username before string_mod remapping, for plugins */
- ALLOC_ARRAY_CLEAR_GC (raw_username, char, USER_PASS_LEN, &gc);
- strcpy (raw_username, up->username);
- string_mod (raw_username, CC_PRINT, CC_CRLF, '_');
-
- /* enforce character class restrictions in username/password */
- string_mod_sslname (up->username, COMMON_NAME_CHAR_CLASS, session->opt->ssl_flags);
- string_mod (up->password, CC_PRINT, CC_CRLF, '_');
-
- /* call plugin(s) and/or script */
#ifdef MANAGEMENT_DEF_AUTH
/* get peer info from control channel */
free (multi->peer_info);
multi->peer_info = read_string_alloc (buf);
-
- if (man_def_auth == KMDA_DEF)
- man_def_auth = verify_user_pass_management (session, up, raw_username);
#endif
- if (plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
- s1 = verify_user_pass_plugin (session, up, raw_username);
- if (session->opt->auth_user_pass_verify_script)
- s2 = verify_user_pass_script (session, up);
-
- /* check sizing of username if it will become our common name */
- if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN)
- {
- msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN);
- s1 = OPENVPN_PLUGIN_FUNC_ERROR;
- }
-
- /* auth succeeded? */
- if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
-#ifdef PLUGIN_DEF_AUTH
- || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED
-#endif
- ) && s2 && man_def_auth != KMDA_ERROR
- && tls_lock_username (multi, up->username))
- {
- ks->authenticated = true;
-#ifdef PLUGIN_DEF_AUTH
- if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
- ks->auth_deferred = true;
-#endif
-#ifdef MANAGEMENT_DEF_AUTH
- if (man_def_auth != KMDA_UNDEF)
- ks->auth_deferred = true;
-#endif
- if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
- set_common_name (session, up->username);
-#ifdef ENABLE_DEF_AUTH
- msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
- 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
- {
- msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer");
- }
+ verify_user_pass(up, multi, session);
CLEAR (*up);
}
else
{
+ /* Session verification should have occurred during TLS negotiation*/
if (!session->verified)
{
msg (D_TLS_ERRORS,
diff --git a/ssl.h b/ssl.h
index 91bc142..0963c37 100644
--- a/ssl.h
+++ b/ssl.h
@@ -77,79 +77,6 @@
#define P_FIRST_OPCODE 1
#define P_LAST_OPCODE 8
-/** @addtogroup control_processor
- * @{ */
-/**
- * @name Control channel negotiation states
- *
- * These states represent the different phases of control channel
- * negotiation between OpenVPN peers. OpenVPN servers and clients
- * progress through the states in a different order, because of their
- * different roles during exchange of random material. The references to
- * the \c key_source2 structure in the list below is only valid if %key
- * method 2 is being used. See the \link key_generation data channel key
- * generation\endlink related page for more information.
- *
- * Clients follow this order:
- * -# \c S_INITIAL, ready to begin three-way handshake and control
- * channel negotiation.
- * -# \c S_PRE_START, have started three-way handshake, waiting for
- * acknowledgment from remote.
- * -# \c S_START, initial three-way handshake complete.
- * -# \c S_SENT_KEY, have sent local part of \c key_source2 random
- * material.
- * -# \c S_GOT_KEY, have received remote part of \c key_source2 random
- * material.
- * -# \c S_ACTIVE, normal operation during remaining handshake window.
- * -# \c S_NORMAL_OP, normal operation.
- *
- * Servers follow the same order, except for \c S_SENT_KEY and \c
- * S_GOT_KEY being reversed, because the server first receives the
- * client's \c key_source2 random material before generating and sending
- * its own.
- *
- * @{
- */
-#define S_ERROR -1 /**< Error state. */
-#define S_UNDEF 0 /**< Undefined state, used after a \c
- * key_state is cleaned up. */
-#define S_INITIAL 1 /**< Initial \c key_state state after
- * initialization by \c key_state_init()
- * before start of three-way handshake. */
-#define S_PRE_START 2 /**< Waiting for the remote OpenVPN peer
- * to acknowledge during the initial
- * three-way handshake. */
-#define S_START 3 /**< Three-way handshake is complete,
- * start of key exchange. */
-#define S_SENT_KEY 4 /**< Local OpenVPN process has sent its
- * part of the key material. */
-#define S_GOT_KEY 5 /**< Local OpenVPN process has received
- * the remote's part of the key
- * material. */
-#define S_ACTIVE 6 /**< Operational \c key_state state
- * immediately after negotiation has
- * completed while still within the
- * handshake window. */
-/* ready to exchange data channel packets */
-#define S_NORMAL_OP 7 /**< Normal operational \c key_state
- * state. */
-/** @} name Control channel negotiation states */
-/** @} addtogroup control_processor */
-
-
-#define DECRYPT_KEY_ENABLED(multi, ks) ((ks)->state >= (S_GOT_KEY - (multi)->opt.server))
- /**< Check whether the \a ks \c key_state
- * is ready to receive data channel
- * packets.
- * @ingroup data_crypto
- *
- * If true, it is safe to assume that
- * this session has been authenticated
- * by TLS.
- *
- * @note This macro only works if
- * S_SENT_KEY + 1 == S_GOT_KEY. */
-
/* Should we aggregate TLS
* acknowledgements, and tack them onto
* control packets? */
@@ -521,15 +448,7 @@ bool tls_send_payload (struct tls_multi *multi,
bool tls_rec_payload (struct tls_multi *multi,
struct buffer *buf);
-#define TLS_AUTHENTICATION_SUCCEEDED 0
-#define TLS_AUTHENTICATION_FAILED 1
-#define TLS_AUTHENTICATION_DEFERRED 2
-#define TLS_AUTHENTICATION_UNDEFINED 3
-int tls_authentication_status (struct tls_multi *multi, const int latency);
-
#ifdef MANAGEMENT_DEF_AUTH
-bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason);
-
static inline char *
tls_get_peer_info(const struct tls_multi *multi)
{
@@ -577,16 +496,6 @@ tls_set_single_session (struct tls_multi *multi)
multi->opt.single_session = true;
}
-static inline const char *
-tls_client_reason (struct tls_multi *multi)
-{
-#ifdef ENABLE_DEF_AUTH
- return multi->client_reason;
-#else
- return NULL;
-#endif
-}
-
/*
* protocol_dump() flags
*/
diff --git a/ssl_common.h b/ssl_common.h
index 408744c..525a1da 100644
--- a/ssl_common.h
+++ b/ssl_common.h
@@ -42,6 +42,65 @@
#define UP_TYPE_AUTH "Auth"
#define UP_TYPE_PRIVATE_KEY "Private Key"
+/** @addtogroup control_processor
+ * @{ */
+/**
+ * @name Control channel negotiation states
+ *
+ * These states represent the different phases of control channel
+ * negotiation between OpenVPN peers. OpenVPN servers and clients
+ * progress through the states in a different order, because of their
+ * different roles during exchange of random material. The references to
+ * the \c key_source2 structure in the list below is only valid if %key
+ * method 2 is being used. See the \link key_generation data channel key
+ * generation\endlink related page for more information.
+ *
+ * Clients follow this order:
+ * -# \c S_INITIAL, ready to begin three-way handshake and control
+ * channel negotiation.
+ * -# \c S_PRE_START, have started three-way handshake, waiting for
+ * acknowledgment from remote.
+ * -# \c S_START, initial three-way handshake complete.
+ * -# \c S_SENT_KEY, have sent local part of \c key_source2 random
+ * material.
+ * -# \c S_GOT_KEY, have received remote part of \c key_source2 random
+ * material.
+ * -# \c S_ACTIVE, normal operation during remaining handshake window.
+ * -# \c S_NORMAL_OP, normal operation.
+ *
+ * Servers follow the same order, except for \c S_SENT_KEY and \c
+ * S_GOT_KEY being reversed, because the server first receives the
+ * client's \c key_source2 random material before generating and sending
+ * its own.
+ *
+ * @{
+ */
+#define S_ERROR -1 /**< Error state. */
+#define S_UNDEF 0 /**< Undefined state, used after a \c
+ * key_state is cleaned up. */
+#define S_INITIAL 1 /**< Initial \c key_state state after
+ * initialization by \c key_state_init()
+ * before start of three-way handshake. */
+#define S_PRE_START 2 /**< Waiting for the remote OpenVPN peer
+ * to acknowledge during the initial
+ * three-way handshake. */
+#define S_START 3 /**< Three-way handshake is complete,
+ * start of key exchange. */
+#define S_SENT_KEY 4 /**< Local OpenVPN process has sent its
+ * part of the key material. */
+#define S_GOT_KEY 5 /**< Local OpenVPN process has received
+ * the remote's part of the key
+ * material. */
+#define S_ACTIVE 6 /**< Operational \c key_state state
+ * immediately after negotiation has
+ * completed while still within the
+ * handshake window. */
+/* ready to exchange data channel packets */
+#define S_NORMAL_OP 7 /**< Normal operational \c key_state
+ * state. */
+/** @} name Control channel negotiation states */
+/** @} addtogroup control_processor */
+
/**
* Container for one half of random material to be used in %key method 2
* \ref key_generation "data channel key generation".
diff --git a/ssl_verify.c b/ssl_verify.c
index b8f66f7..16d294d 100644
--- a/ssl_verify.c
+++ b/ssl_verify.c
@@ -37,6 +37,33 @@
#include "ssl_verify_openssl.h"
#endif
+/** Legal characters in a common name */
+#define COMMON_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_SLASH)
+
+/** Maximum length of common name */
+#define TLS_USERNAME_LEN 64
+
+static void
+string_mod_sslname (char *str, const unsigned int restrictive_flags, const unsigned int ssl_flags)
+{
+ if (ssl_flags & SSLF_NO_NAME_REMAPPING)
+ string_mod (str, CC_PRINT, CC_CRLF, '_');
+ else
+ string_mod (str, restrictive_flags, 0, '_');
+}
+
+/*
+ * Export the untrusted IP address and port to the environment
+ */
+static void
+setenv_untrusted (struct tls_session *session)
+{
+ setenv_link_socket_actual (session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT);
+}
+
+/*
+ * Remove authenticated state from all sessions in the given tunnel
+ */
static void
tls_deauthenticate (struct tls_multi *multi)
{
@@ -97,6 +124,43 @@ tls_lock_common_name (struct tls_multi *multi)
multi->locked_cn = string_alloc (cn, NULL);
}
+static bool
+tls_lock_username (struct tls_multi *multi, const char *username)
+{
+ if (multi->locked_username)
+ {
+ if (!username || strcmp (username, multi->locked_username))
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled",
+ multi->locked_username,
+ np(username));
+
+ /* disable the tunnel */
+ tls_deauthenticate (multi);
+ return false;
+ }
+ }
+ else
+ {
+ if (username)
+ multi->locked_username = string_alloc (username, NULL);
+ }
+ return true;
+}
+
+const char *
+tls_username (const struct tls_multi *multi, const bool null)
+{
+ const char *ret = NULL;
+ if (multi)
+ ret = multi->locked_username;
+ if (ret && strlen (ret))
+ return ret;
+ else if (null)
+ return NULL;
+ else
+ return "UNDEF";
+}
void
cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash)
@@ -201,6 +265,495 @@ tls_lock_cert_hash_set (struct tls_multi *multi)
}
+/* ***************************************************************************
+ * Functions for the management of deferred authentication when using
+ * user/password authentication.
+ *************************************************************************** */
+
+#ifdef ENABLE_DEF_AUTH
+/* key_state_test_auth_control_file return values,
+ NOTE: acf_merge indexing depends on these values */
+#define ACF_UNDEFINED 0
+#define ACF_SUCCEEDED 1
+#define ACF_DISABLED 2
+#define ACF_FAILED 3
+#endif
+
+#ifdef MANAGEMENT_DEF_AUTH
+void
+man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason)
+{
+ if (multi->client_reason)
+ {
+ free (multi->client_reason);
+ multi->client_reason = NULL;
+ }
+ if (client_reason && strlen (client_reason))
+ multi->client_reason = string_alloc (client_reason, NULL);
+}
+
+static inline unsigned int
+man_def_auth_test (const struct key_state *ks)
+{
+ if (management_enable_def_auth (management))
+ return ks->mda_status;
+ else
+ return ACF_DISABLED;
+}
+#endif
+
+#ifdef PLUGIN_DEF_AUTH
+
+/*
+ * auth_control_file functions
+ */
+
+void
+key_state_rm_auth_control_file (struct key_state *ks)
+{
+ if (ks && ks->auth_control_file)
+ {
+ delete_file (ks->auth_control_file);
+ free (ks->auth_control_file);
+ ks->auth_control_file = NULL;
+ }
+}
+
+static void
+key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options *opt)
+{
+ struct gc_arena gc = gc_new ();
+ const char *acf;
+
+ key_state_rm_auth_control_file (ks);
+ acf = create_temp_file (opt->tmp_dir, "acf", &gc);
+ if (acf) {
+ ks->auth_control_file = string_alloc (acf, NULL);
+ setenv_str (opt->es, "auth_control_file", ks->auth_control_file);
+ } /* FIXME: Should have better error handling? */
+
+ gc_free (&gc);
+}
+
+static unsigned int
+key_state_test_auth_control_file (struct key_state *ks)
+{
+ if (ks && ks->auth_control_file)
+ {
+ unsigned int ret = ks->auth_control_status;
+ if (ret == ACF_UNDEFINED)
+ {
+ FILE *fp = fopen (ks->auth_control_file, "r");
+ if (fp)
+ {
+ const int c = fgetc (fp);
+ if (c == '1')
+ ret = ACF_SUCCEEDED;
+ else if (c == '0')
+ ret = ACF_FAILED;
+ fclose (fp);
+ ks->auth_control_status = ret;
+ }
+ }
+ return ret;
+ }
+ return ACF_DISABLED;
+}
+
+#endif
+
+/*
+ * Return current session authentication state. Return
+ * value is TLS_AUTHENTICATION_x.
+ */
+
+int
+tls_authentication_status (struct tls_multi *multi, const int latency)
+{
+ bool deferred = false;
+ bool success = false;
+ bool active = false;
+
+#ifdef ENABLE_DEF_AUTH
+ static const unsigned char acf_merge[] =
+ {
+ ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_UNDEFINED */
+ ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_SUCCEEDED */
+ ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_DISABLED */
+ ACF_FAILED, /* s1=ACF_UNDEFINED s2=ACF_FAILED */
+ ACF_UNDEFINED, /* s1=ACF_SUCCEEDED s2=ACF_UNDEFINED */
+ ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_SUCCEEDED */
+ ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_DISABLED */
+ ACF_FAILED, /* s1=ACF_SUCCEEDED s2=ACF_FAILED */
+ ACF_UNDEFINED, /* s1=ACF_DISABLED s2=ACF_UNDEFINED */
+ ACF_SUCCEEDED, /* s1=ACF_DISABLED s2=ACF_SUCCEEDED */
+ ACF_DISABLED, /* s1=ACF_DISABLED s2=ACF_DISABLED */
+ ACF_FAILED, /* s1=ACF_DISABLED s2=ACF_FAILED */
+ ACF_FAILED, /* s1=ACF_FAILED s2=ACF_UNDEFINED */
+ ACF_FAILED, /* s1=ACF_FAILED s2=ACF_SUCCEEDED */
+ ACF_FAILED, /* s1=ACF_FAILED s2=ACF_DISABLED */
+ ACF_FAILED /* s1=ACF_FAILED s2=ACF_FAILED */
+ };
+#endif /* ENABLE_DEF_AUTH */
+
+ if (multi)
+ {
+ int i;
+
+#ifdef ENABLE_DEF_AUTH
+ if (latency && multi->tas_last && multi->tas_last + latency >= now)
+ return TLS_AUTHENTICATION_UNDEFINED;
+ multi->tas_last = now;
+#endif /* ENABLE_DEF_AUTH */
+
+ for (i = 0; i < KEY_SCAN_SIZE; ++i)
+ {
+ struct key_state *ks = multi->key_scan[i];
+ if (DECRYPT_KEY_ENABLED (multi, ks))
+ {
+ active = true;
+ if (ks->authenticated)
+ {
+#ifdef ENABLE_DEF_AUTH
+ unsigned int s1 = ACF_DISABLED;
+ unsigned int s2 = ACF_DISABLED;
+#ifdef PLUGIN_DEF_AUTH
+ s1 = key_state_test_auth_control_file (ks);
+#endif /* PLUGIN_DEF_AUTH */
+#ifdef MANAGEMENT_DEF_AUTH
+ s2 = man_def_auth_test (ks);
+#endif /* MANAGEMENT_DEF_AUTH */
+ ASSERT (s1 < 4 && s2 < 4);
+ switch (acf_merge[(s1<<2) + s2])
+ {
+ case ACF_SUCCEEDED:
+ case ACF_DISABLED:
+ success = true;
+ ks->auth_deferred = false;
+ break;
+ case ACF_UNDEFINED:
+ if (now < ks->auth_deferred_expire)
+ deferred = true;
+ break;
+ case ACF_FAILED:
+ ks->authenticated = false;
+ break;
+ default:
+ ASSERT (0);
+ }
+#else /* !ENABLE_DEF_AUTH */
+ success = true;
+#endif /* ENABLE_DEF_AUTH */
+ }
+ }
+ }
+ }
+
+#if 0
+ dmsg (D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred);
+#endif
+
+ if (success)
+ return TLS_AUTHENTICATION_SUCCEEDED;
+ else if (!active || deferred)
+ return TLS_AUTHENTICATION_DEFERRED;
+ else
+ return TLS_AUTHENTICATION_FAILED;
+}
+
+#ifdef MANAGEMENT_DEF_AUTH
+/*
+ * For deferred auth, this is where the management interface calls (on server)
+ * to indicate auth failure/success.
+ */
+bool
+tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason)
+{
+ bool ret = false;
+ if (multi)
+ {
+ int i;
+ man_def_auth_set_client_reason (multi, client_reason);
+ for (i = 0; i < KEY_SCAN_SIZE; ++i)
+ {
+ struct key_state *ks = multi->key_scan[i];
+ if (ks->mda_key_id == mda_key_id)
+ {
+ ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED;
+ ret = true;
+ }
+ }
+ }
+ return ret;
+}
+#endif
+
+
+/* ****************************************************************************
+ * Functions to verify username and password
+ *
+ * Authenticate a client using username/password.
+ * Runs on server.
+ *
+ * If you want to add new authentication methods,
+ * this is the place to start.
+ *************************************************************************** */
+
+/*
+ * Verify the user name and password using a script
+ */
+static bool
+verify_user_pass_script (struct tls_session *session, const struct user_pass *up)
+{
+ struct gc_arena gc = gc_new ();
+ struct argv argv = argv_new ();
+ const char *tmp_file = "";
+ bool ret = false;
+
+ /* Is username defined? */
+ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
+ {
+ /* Set environmental variables prior to calling script */
+ setenv_str (session->opt->es, "script_type", "user-pass-verify");
+
+ if (session->opt->auth_user_pass_verify_script_via_file)
+ {
+ struct status_output *so;
+
+ tmp_file = create_temp_file (session->opt->tmp_dir, "up", &gc);
+ if( tmp_file ) {
+ so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
+ status_printf (so, "%s", up->username);
+ status_printf (so, "%s", up->password);
+ if (!status_close (so))
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s",
+ tmp_file);
+ goto done;
+ }
+ } else {
+ msg (D_TLS_ERRORS, "TLS Auth Error: could not create write "
+ "username/password to temp file");
+ }
+ }
+ else
+ {
+ setenv_str (session->opt->es, "username", up->username);
+ setenv_str (session->opt->es, "password", up->password);
+ }
+
+ /* setenv incoming cert common name for script */
+ setenv_str (session->opt->es, "common_name", session->common_name);
+
+ /* setenv client real IP address */
+ setenv_untrusted (session);
+
+ /* format command line */
+ argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
+
+ /* call command */
+ ret = openvpn_run_script (&argv, session->opt->es, 0,
+ "--auth-user-pass-verify");
+
+ if (!session->opt->auth_user_pass_verify_script_via_file)
+ setenv_del (session->opt->es, "password");
+ }
+ else
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username");
+ }
+
+ done:
+ if (tmp_file && strlen (tmp_file) > 0)
+ delete_file (tmp_file);
+
+ argv_reset (&argv);
+ gc_free (&gc);
+ return ret;
+}
+
+/*
+ * Verify the username and password using a plugin
+ */
+static int
+verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
+{
+ int retval = OPENVPN_PLUGIN_FUNC_ERROR;
+ struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
+
+ /* Is username defined? */
+ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
+ {
+ /* set username/password in private env space */
+ setenv_str (session->opt->es, "username", raw_username);
+ setenv_str (session->opt->es, "password", up->password);
+
+ /* setenv incoming cert common name for script */
+ setenv_str (session->opt->es, "common_name", session->common_name);
+
+ /* setenv client real IP address */
+ setenv_untrusted (session);
+
+#ifdef PLUGIN_DEF_AUTH
+ /* generate filename for deferred auth control file */
+ key_state_gen_auth_control_file (ks, session->opt);
+#endif
+
+ /* call command */
+ retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es, -1, NULL);
+
+#ifdef PLUGIN_DEF_AUTH
+ /* purge auth control filename (and file itself) for non-deferred returns */
+ if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
+ key_state_rm_auth_control_file (ks);
+#endif
+
+ setenv_del (session->opt->es, "password");
+ setenv_str (session->opt->es, "username", up->username);
+ }
+ else
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username");
+ }
+
+ return retval;
+}
+
+
+#ifdef MANAGEMENT_DEF_AUTH
+/*
+ * MANAGEMENT_DEF_AUTH internal ssl_verify.c status codes
+ */
+#define KMDA_ERROR 0
+#define KMDA_SUCCESS 1
+#define KMDA_UNDEF 2
+#define KMDA_DEF 3
+
+static int
+verify_user_pass_management (struct tls_session *session, const struct user_pass *up, const char *raw_username)
+{
+ int retval = KMDA_ERROR;
+ struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
+
+ /* Is username defined? */
+ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
+ {
+ /* set username/password in private env space */
+ setenv_str (session->opt->es, "username", raw_username);
+ setenv_str (session->opt->es, "password", up->password);
+
+ /* setenv incoming cert common name for script */
+ setenv_str (session->opt->es, "common_name", session->common_name);
+
+ /* setenv client real IP address */
+ setenv_untrusted (session);
+
+ if (management)
+ management_notify_client_needing_auth (management, ks->mda_key_id, session->opt->mda_context, session->opt->es);
+
+ setenv_del (session->opt->es, "password");
+ setenv_str (session->opt->es, "username", up->username);
+
+ retval = KMDA_SUCCESS;
+ }
+ else
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username");
+ }
+
+ return retval;
+}
+#endif
+
+/*
+ * Main username/password verification entry point
+ */
+void
+verify_user_pass(struct user_pass *up, struct tls_multi *multi,
+ struct tls_session *session)
+{
+ int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
+ bool s2 = true;
+ struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
+
+ struct gc_arena gc = gc_new ();
+ char *raw_username;
+
+#ifdef MANAGEMENT_DEF_AUTH
+ int man_def_auth = KMDA_UNDEF;
+
+ if (management_enable_def_auth (management))
+ man_def_auth = KMDA_DEF;
+#endif
+
+ /* preserve raw username before string_mod remapping, for plugins */
+ ALLOC_ARRAY_CLEAR_GC (raw_username, char, USER_PASS_LEN, &gc);
+ strcpy (raw_username, up->username);
+ string_mod (raw_username, CC_PRINT, CC_CRLF, '_');
+
+ /* enforce character class restrictions in username/password */
+ string_mod_sslname (up->username, COMMON_NAME_CHAR_CLASS, session->opt->ssl_flags);
+ string_mod (up->password, CC_PRINT, CC_CRLF, '_');
+
+ /* call plugin(s) and/or script */
+#ifdef MANAGEMENT_DEF_AUTH
+ if (man_def_auth == KMDA_DEF)
+ man_def_auth = verify_user_pass_management (session, up, raw_username);
+#endif
+ if (plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
+ s1 = verify_user_pass_plugin (session, up, raw_username);
+ if (session->opt->auth_user_pass_verify_script)
+ s2 = verify_user_pass_script (session, up);
+
+ /* check sizing of username if it will become our common name */
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN)
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN);
+ s1 = OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+
+ /* auth succeeded? */
+ if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
+#ifdef PLUGIN_DEF_AUTH
+ || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED
+#endif
+ ) && s2
+#ifdef MANAGEMENT_DEF_AUTH
+ && man_def_auth != KMDA_ERROR
+#endif
+ && tls_lock_username (multi, up->username))
+ {
+ ks->authenticated = true;
+#ifdef PLUGIN_DEF_AUTH
+ if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
+ ks->auth_deferred = true;
+#endif
+#ifdef MANAGEMENT_DEF_AUTH
+ if (man_def_auth != KMDA_UNDEF)
+ ks->auth_deferred = true;
+#endif
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
+ set_common_name (session, up->username);
+#ifdef ENABLE_DEF_AUTH
+ msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
+ 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
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer");
+ }
+
+ gc_free (&gc);
+}
+
void
verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session)
{
diff --git a/ssl_verify.h b/ssl_verify.h
index b76a16a..ad94bc6 100644
--- a/ssl_verify.h
+++ b/ssl_verify.h
@@ -58,6 +58,36 @@ struct cert_hash_set {
};
+#define TLS_AUTHENTICATION_SUCCEEDED 0
+#define TLS_AUTHENTICATION_FAILED 1
+#define TLS_AUTHENTICATION_DEFERRED 2
+#define TLS_AUTHENTICATION_UNDEFINED 3
+
+/*
+ * Return current session authentication state. Return
+ * value is TLS_AUTHENTICATION_x.
+ *
+ * TODO: document this function
+ */
+int tls_authentication_status (struct tls_multi *multi, const int latency);
+
+/** Check whether the \a ks \c key_state is ready to receive data channel
+ * packets.
+ * @ingroup data_crypto
+ *
+ * If true, it is safe to assume that this session has been authenticated
+ * by TLS.
+ *
+ * @note This macro only works if S_SENT_KEY + 1 == S_GOT_KEY. */
+#define DECRYPT_KEY_ENABLED(multi, ks) ((ks)->state >= (S_GOT_KEY - (multi)->opt.server))
+
+/**
+ * Remove the given key state's auth control file, if it exists.
+ *
+ * @param ks The key state the remove the file for
+ */
+void key_state_rm_auth_control_file (struct key_state *ks);
+
/**
* Frees the given set of certificate hashes.
*
@@ -87,7 +117,13 @@ void tls_lock_common_name (struct tls_multi *multi);
*/
const char *tls_common_name (const struct tls_multi* multi, const bool null);
-void tls_set_common_name (struct tls_multi *multi, const char *common_name);
+/**
+ * Returns the username field for the given tunnel
+ *
+ * @param multi The tunnel to return the username for
+ * @param null Whether null may be returned. If not, "UNDEF" will be returned.
+ */
+const char *tls_username (const struct tls_multi *multi, const bool null);
#ifdef ENABLE_PF
@@ -119,6 +155,38 @@ tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *
#endif
/**
+ * Returns whether or not the server should check for username/password
+ *
+ * @param session The current TLS session
+ *
+ * @return true if username and password verification is enabled,
+ * false if not.
+ *
+ */
+static inline bool verify_user_pass_enabled(struct tls_session *session)
+{
+ return (session->opt->auth_user_pass_verify_script
+ || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
+ || management_enable_def_auth (management));
+}
+
+/**
+ * Verify the given username and password, using either an external script, a
+ * plugin, or the management interface.
+ *
+ * If authentication succeeds, the appropriate state is filled into the
+ * session's primary key state's authenticated field. Authentication may also
+ * be deferred, in which case the key state's auth_deferred field is filled in.
+ *
+ * @param up The username and password to verify.
+ * @param multi The TLS multi structure to verify usernames against.
+ * @param session The current TLS session
+ *
+ */
+void verify_user_pass(struct user_pass *up, struct tls_multi *multi,
+ struct tls_session *session);
+
+/**
* Perform final authentication checks, including locking of the cn, the allowed
* certificate hashes, and whether a client config entry exists in the
* client config directory.
@@ -129,5 +197,24 @@ tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *
*/
void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session);
+/*
+ * TODO: document
+ */
+#ifdef MANAGEMENT_DEF_AUTH
+bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason);
+void man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason);
+#endif
+
+static inline const char *
+tls_client_reason (struct tls_multi *multi)
+{
+#ifdef ENABLE_DEF_AUTH
+ return multi->client_reason;
+#else
+ return NULL;
+#endif
+}
+
#endif /* SSL_VERIFY_H_ */
+