diff options
Diffstat (limited to 'src/openvpn/ssl_verify.c')
-rw-r--r-- | src/openvpn/ssl_verify.c | 580 |
1 files changed, 277 insertions, 303 deletions
diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index c7e595e..4f3b61d 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> - * Copyright (C) 2010-2018 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2021 OpenVPN Inc <sales@openvpn.net> + * Copyright (C) 2010-2021 Fox Crypto B.V. <openvpn@foxcrypto.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -34,40 +34,26 @@ #include "syshead.h" -#ifdef ENABLE_CRYPTO - -#include "misc.h" +#include "base64.h" #include "manage.h" #include "otime.h" -#include "base64.h" +#include "run_command.h" #include "ssl_verify.h" #include "ssl_verify_backend.h" #ifdef ENABLE_CRYPTO_OPENSSL #include "ssl_verify_openssl.h" #endif +#include "auth_token.h" +#include "push.h" /** Maximum length of common name */ #define TLS_USERNAME_LEN 64 -/** Legal characters in an X509 name with --compat-names */ -#define X509_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_SLASH|CC_COLON|CC_EQUAL) - -/** Legal characters in a common name with --compat-names */ -#define COMMON_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_SLASH) - static void -string_mod_remap_name(char *str, const unsigned int restrictive_flags) +string_mod_remap_name(char *str) { - if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NAMES) - && !compat_flag(COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING)) - { - string_mod(str, restrictive_flags, 0, '_'); - } - else - { - string_mod(str, CC_PRINT, CC_CRLF, '_'); - } + string_mod(str, CC_PRINT, CC_CRLF, '_'); } /* @@ -79,28 +65,6 @@ setenv_untrusted(struct tls_session *session) setenv_link_socket_actual(session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT); } - -/** - * Wipes the authentication token out of the memory, frees and cleans up related buffers and flags - * - * @param multi Pointer to a multi object holding the auth_token variables - */ -static void -wipe_auth_token(struct tls_multi *multi) -{ - if(multi) - { - if (multi->auth_token) - { - secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); - free(multi->auth_token); - } - multi->auth_token = NULL; - multi->auth_token_sent = false; - } -} - - /* * Remove authenticated state from all sessions in the given tunnel */ @@ -114,7 +78,7 @@ tls_deauthenticate(struct tls_multi *multi) { for (int j = 0; j < KS_SIZE; ++j) { - multi->session[i].key[j].authenticated = false; + multi->session[i].key[j].authenticated = KS_AUTH_FALSE; } } } @@ -524,7 +488,7 @@ verify_cert_call_plugin(const struct plugin_list *plugins, struct env_set *es, ret = plugin_call_ssl(plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, es, cert_depth, cert); - argv_reset(&argv); + argv_free(&argv); if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS) { @@ -549,9 +513,9 @@ verify_cert_export_cert(openvpn_x509_cert_t *peercert, const char *tmp_dir, stru /* create tmp file to store peer cert */ if (!tmp_dir - || !(peercert_filename = create_temp_file(tmp_dir, "pcf", gc))) + || !(peercert_filename = platform_create_temp_file(tmp_dir, "pcf", gc))) { - msg (M_WARN, "Failed to create peer cert file"); + msg(M_NONFATAL, "Failed to create peer cert file"); return NULL; } @@ -559,13 +523,16 @@ verify_cert_export_cert(openvpn_x509_cert_t *peercert, const char *tmp_dir, stru peercert_file = fopen(peercert_filename, "w+"); if (!peercert_file) { - msg(M_ERR, "Failed to open temporary file : %s", peercert_filename); + msg(M_NONFATAL|M_ERRNO, "Failed to open temporary file: %s", + peercert_filename); return NULL; } if (SUCCESS != x509_write_pem(peercert_file, peercert)) { - msg(M_ERR, "Error writing PEM file containing certificate"); + msg(M_NONFATAL, "Error writing PEM file containing certificate"); + (void) platform_unlink(peercert_filename); + peercert_filename = NULL; } fclose(peercert_file); @@ -614,7 +581,7 @@ verify_cert_call_command(const char *verify_command, struct env_set *es, cleanup: gc_free(&gc); - argv_reset(&argv); + argv_free(&argv); if (ret) { @@ -632,7 +599,8 @@ cleanup: * check peer cert against CRL directory */ static result_t -verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert) +verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert, + const char *subject, int cert_depth) { result_t ret = FAILURE; char fn[256]; @@ -640,6 +608,12 @@ verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert) struct gc_arena gc = gc_new(); char *serial = backend_x509_get_serial(cert, &gc); + if (!serial) + { + msg(D_HANDSHAKE, "VERIFY CRL: depth=%d, %s, serial number is not available", + cert_depth, subject); + goto cleanup; + } if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", crl_dir, OS_SPECIFIC_DIRSEP, serial)) { @@ -649,7 +623,8 @@ verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert) fd = platform_open(fn, O_RDONLY, 0); if (fd >= 0) { - msg(D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial); + msg(D_HANDSHAKE, "VERIFY CRL: depth=%d, %s, serial=%s is revoked", + cert_depth, subject, serial); goto cleanup; } @@ -689,7 +664,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep } /* enforce character class restrictions in X509 name */ - string_mod_remap_name(subject, X509_NAME_CHAR_CLASS); + string_mod_remap_name(subject); string_replace_leading(subject, '-', '_'); /* extract the username (default is CN) */ @@ -709,7 +684,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep } /* enforce character class restrictions in common name */ - string_mod_remap_name(common_name, COMMON_NAME_CHAR_CLASS); + string_mod_remap_name(common_name); /* warn if cert chain is too deep */ if (cert_depth >= MAX_CERT_DEPTH) @@ -725,24 +700,24 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep switch (opt->verify_hash_algo) { - case MD_SHA1: - ca_hash = x509_get_sha1_fingerprint(cert, &gc); - break; - - case MD_SHA256: - ca_hash = x509_get_sha256_fingerprint(cert, &gc); - break; - - default: - /* This should normally not happen at all; the algorithm used - * is parsed by add_option() [options.c] and set to a predefined - * value in an enumerated type. So if this unlikely scenario - * happens, consider this a failure - */ - msg(M_WARN, "Unexpected invalid algorithm used with " - "--verify-hash (%i)", opt->verify_hash_algo); - ret = FAILURE; - goto cleanup; + case MD_SHA1: + ca_hash = x509_get_sha1_fingerprint(cert, &gc); + break; + + case MD_SHA256: + ca_hash = x509_get_sha256_fingerprint(cert, &gc); + break; + + default: + /* This should normally not happen at all; the algorithm used + * is parsed by add_option() [options.c] and set to a predefined + * value in an enumerated type. So if this unlikely scenario + * happens, consider this a failure + */ + msg(M_WARN, "Unexpected invalid algorithm used with " + "--verify-hash (%i)", opt->verify_hash_algo); + ret = FAILURE; + goto cleanup; } if (memcmp(BPTR(&ca_hash), opt->verify_hash, BLEN(&ca_hash))) @@ -791,7 +766,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep { if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR) { - if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert)) + if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert, subject, cert_depth)) { goto cleanup; } @@ -836,9 +811,8 @@ cleanup: #define ACF_FAILED 3 #endif -#ifdef MANAGEMENT_DEF_AUTH void -man_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reason) +auth_set_client_reason(struct tls_multi *multi, const char *client_reason) { if (multi->client_reason) { @@ -847,11 +821,12 @@ man_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reaso } if (client_reason && strlen(client_reason)) { - /* FIXME: Last alloc will never be freed */ multi->client_reason = string_alloc(client_reason, NULL); } } +#ifdef MANAGEMENT_DEF_AUTH + static inline unsigned int man_def_auth_test(const struct key_state *ks) { @@ -889,7 +864,7 @@ key_state_gen_auth_control_file(struct key_state *ks, const struct tls_options * struct gc_arena gc = gc_new(); key_state_rm_auth_control_file(ks); - const char *acf = create_temp_file(opt->tmp_dir, "acf", &gc); + const char *acf = platform_create_temp_file(opt->tmp_dir, "acf", &gc); if (acf) { ks->auth_control_file = string_alloc(acf, NULL); @@ -931,6 +906,39 @@ key_state_test_auth_control_file(struct key_state *ks) #endif /* ifdef PLUGIN_DEF_AUTH */ +/* This function is called when a session's primary key state first becomes KS_TRUE */ +void ssl_session_fully_authenticated(struct tls_multi *multi, struct tls_session* session) +{ + struct key_state *ks = &session->key[KS_PRIMARY]; + if (ks->key_id == 0) + { + /* A key id of 0 indicates a new session and the client will + * get the auth-token as part of the initial push reply */ + return; + } + + /* + * Auth token already sent to client, update auth-token on client. + * The initial auth-token is sent as part of the push message, for this + * update we need to schedule an extra push message. + * + * Otherwise the auth-token get pushed out as part of the "normal" + * push-reply + */ + if (multi->auth_token_initial) + { + /* + * We do not explicitly schedule the sending of the + * control message here but control message are only + * postponed when the control channel is not yet fully + * established and furthermore since this is called in + * the middle of authentication, there are other messages + * (new data channel keys) that are sent anyway and will + * trigger scheduling + */ + send_push_reply_auth_token(multi); + } +} /* * Return current session authentication state. Return * value is TLS_AUTHENTICATION_x. @@ -983,7 +991,7 @@ tls_authentication_status(struct tls_multi *multi, const int latency) if (DECRYPT_KEY_ENABLED(multi, ks)) { active = true; - if (ks->authenticated) + if (ks->authenticated > KS_AUTH_FALSE) { #ifdef ENABLE_DEF_AUTH unsigned int s1 = ACF_DISABLED; @@ -1000,7 +1008,13 @@ tls_authentication_status(struct tls_multi *multi, const int latency) case ACF_SUCCEEDED: case ACF_DISABLED: success = true; - ks->auth_deferred = false; + /* i=0 is the TM_ACTIVE/KS_PRIMARY session */ + if (i == 0 && ks->authenticated == KS_AUTH_DEFERRED) + { + ssl_session_fully_authenticated(multi, + &multi->session[TM_ACTIVE]); + } + ks->authenticated = KS_AUTH_TRUE; break; case ACF_UNDEFINED: @@ -1011,7 +1025,7 @@ tls_authentication_status(struct tls_multi *multi, const int latency) break; case ACF_FAILED: - ks->authenticated = false; + ks->authenticated = KS_AUTH_FALSE; break; default: @@ -1055,7 +1069,7 @@ tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, con if (multi) { int i; - man_def_auth_set_client_reason(multi, client_reason); + auth_set_client_reason(multi, client_reason); for (i = 0; i < KEY_SCAN_SIZE; ++i) { struct key_state *ks = multi->key_scan[i]; @@ -1085,79 +1099,66 @@ tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, con * Verify the user name and password using a script */ static bool -verify_user_pass_script(struct tls_session *session, const struct user_pass *up) +verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, + 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"); + + /* format command line */ + argv_parse_cmd(&argv, session->opt->auth_user_pass_verify_script); + + if (session->opt->auth_user_pass_verify_script_via_file) { - /* Set environmental variables prior to calling script */ - setenv_str(session->opt->es, "script_type", "user-pass-verify"); + struct status_output *so; - if (session->opt->auth_user_pass_verify_script_via_file) + tmp_file = platform_create_temp_file(session->opt->tmp_dir, "up", + &gc); + if (tmp_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)) { - 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"); + msg(D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s", + tmp_file); + goto done; } + /* pass temp file name to script */ + argv_printf_cat(&argv, "%s", tmp_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_parse_cmd(&argv, session->opt->auth_user_pass_verify_script); - argv_printf_cat(&argv, "%s", 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"); + msg(D_TLS_ERRORS, "TLS Auth Error: could not create write " + "username/password to temp file"); } } else { - msg(D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username"); + setenv_str(session->opt->es, "password", up->password); } + /* 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"); + } done: if (tmp_file && strlen(tmp_file) > 0) { platform_unlink(tmp_file); } - argv_reset(&argv); + argv_free(&argv); gc_free(&gc); return ret; } @@ -1166,59 +1167,40 @@ done: * 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) +verify_user_pass_plugin(struct tls_session *session, struct tls_multi *multi, + const struct user_pass *up) { int retval = OPENVPN_PLUGIN_FUNC_ERROR; #ifdef PLUGIN_DEF_AUTH struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ #endif - /* 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 ? raw_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); + /* set password in private env space */ + setenv_str(session->opt->es, "password", up->password); #ifdef PLUGIN_DEF_AUTH - /* generate filename for deferred auth control file */ - if (!key_state_gen_auth_control_file(ks, session->opt)) - { - msg (D_TLS_ERRORS, "TLS Auth Error (%s): " - "could not create deferred auth control file", __func__); - goto cleanup; - } + /* generate filename for deferred auth control file */ + if (!key_state_gen_auth_control_file(ks, session->opt)) + { + msg(D_TLS_ERRORS, "TLS Auth Error (%s): " + "could not create deferred auth control file", __func__); + return retval; + } #endif - /* call command */ - retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); + /* call command */ + retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); #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"); - if (raw_username) - { - setenv_str(session->opt->es, "username", up->username); - } - } - else + /* purge auth control filename (and file itself) for non-deferred returns */ + if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) { - msg(D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username"); + key_state_rm_auth_control_file(ks); } +#endif + + setenv_del(session->opt->es, "password"); -cleanup: return retval; } @@ -1233,17 +1215,37 @@ cleanup: #define KMDA_DEF 3 static int -verify_user_pass_management(struct tls_session *session, const struct user_pass *up, const char *raw_username) +verify_user_pass_management(struct tls_session *session, + struct tls_multi *multi, + const struct user_pass *up) { int retval = KMDA_ERROR; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + /* set username/password in private env space */ + setenv_str(session->opt->es, "password", up->password); + + 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"); + + retval = KMDA_SUCCESS; + + return retval; +} +#endif /* ifdef MANAGEMENT_DEF_AUTH */ + +static bool +set_verify_user_pass_env(struct user_pass *up, struct tls_multi *multi, + struct tls_session *session) +{ /* 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 ? raw_username : up->username)); - setenv_str(session->opt->es, "password", up->password); + setenv_str(session->opt->es, "username", up->username); /* setenv incoming cert common name for script */ setenv_str(session->opt->es, "common_name", session->common_name); @@ -1251,30 +1253,25 @@ verify_user_pass_management(struct tls_session *session, const struct user_pass /* 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"); - if (raw_username) - { - setenv_str(session->opt->es, "username", up->username); - } - - retval = KMDA_SUCCESS; + /* + * if we are using auth-gen-token, send also the session id of auth gen token to + * allow the management to figure out if it is a new session or a continued one + */ + add_session_token_env(session, multi, up); + return true; } else { - msg(D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username"); + msg(D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username"); + return false; } - - return retval; } -#endif /* ifdef MANAGEMENT_DEF_AUTH */ /* * 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, @@ -1284,9 +1281,6 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, bool s2 = true; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - struct gc_arena gc = gc_new(); - char *raw_username = NULL; - #ifdef MANAGEMENT_DEF_AUTH int man_def_auth = KMDA_UNDEF; @@ -1296,101 +1290,90 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, } #endif - /* - * Preserve the raw username before string_mod remapping, for plugins - * and management clients when in --compat-names mode - */ - if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NAMES)) - { - 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_remap_name(up->username, COMMON_NAME_CHAR_CLASS); + string_mod_remap_name(up->username); string_mod(up->password, CC_PRINT, CC_CRLF, '_'); - /* If server is configured with --auth-gen-token and we have an - * authentication token for this client, this authentication + /* + * If auth token succeeds we skip the auth + * methods unless otherwise specified + */ + bool skip_auth = false; + + /* + * If server is configured with --auth-gen-token and the client sends + * something that looks like an authentication token, this * round will be done internally using the token instead of * calling any external authentication modules. */ - if (session->opt->auth_token_generate && multi->auth_token_sent - && NULL != multi->auth_token) + if (session->opt->auth_token_generate && is_auth_token(up->password)) { - unsigned int ssl_flags = session->opt->ssl_flags; - - /* Ensure that the username has not changed */ - if (!tls_lock_username(multi, up->username)) - { - /* auth-token cleared in tls_lock_username() on failure */ - ks->authenticated = false; - goto done; - } - - /* If auth-token lifetime has been enabled, - * ensure the token has not expired - */ - if (session->opt->auth_token_lifetime > 0 - && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now) + ks->auth_token_state_flags = verify_auth_token(up, multi, session); + if (session->opt->auth_token_call_auth) { - msg(D_HANDSHAKE, "Auth-token for client expired\n"); - wipe_auth_token(multi); - ks->authenticated = false; - goto done; + /* + * we do not care about the result here because it is + * the responsibility of the external authentication to + * decide what to do with the result + */ } - - /* The core authentication of the token itself */ - if (memcmp_constant_time(multi->auth_token, up->password, - strlen(multi->auth_token)) != 0) + else if (ks->auth_token_state_flags == AUTH_TOKEN_HMAC_OK) { - ks->authenticated = false; - tls_deauthenticate(multi); - - msg(D_TLS_ERRORS, "TLS Auth Error: Auth-token verification " - "failed for username '%s' %s", up->username, - (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + /* + * We do not want the EXPIRED or EMPTY USER flags here so check + * for equality with AUTH_TOKEN_HMAC_OK + */ + msg(M_WARN, "TLS: Username/auth-token authentication " + "succeeded for username '%s'", + up->username); + skip_auth = true; } else { - ks->authenticated = true; - - if (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) - { - set_common_name(session, up->username); - } - msg(D_HANDSHAKE, "TLS: Username/auth-token authentication " - "succeeded for username '%s' %s", - up->username, - (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + wipe_auth_token(multi); + ks->authenticated = KS_AUTH_FALSE; + msg(M_WARN, "TLS: Username/auth-token authentication " + "failed for username '%s'", up->username); + return; } - goto done; } - /* call plugin(s) and/or script */ -#ifdef MANAGEMENT_DEF_AUTH - if (man_def_auth == KMDA_DEF) + /* Set the environment variables used by all auth variants */ + if (!set_verify_user_pass_env(up, multi, session)) { - 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); + skip_auth = true; + s1 = OPENVPN_PLUGIN_FUNC_ERROR; } - if (session->opt->auth_user_pass_verify_script) + + /* call plugin(s) and/or script */ + if (!skip_auth) { - s2 = verify_user_pass_script(session, up); +#ifdef MANAGEMENT_DEF_AUTH + if (man_def_auth==KMDA_DEF) + { + man_def_auth = verify_user_pass_management(session, multi, up); + } +#endif + if (plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)) + { + s1 = verify_user_pass_plugin(session, multi, up); + } + + if (session->opt->auth_user_pass_verify_script) + { + s2 = verify_user_pass_script(session, multi, 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) + 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); + 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 @@ -1402,67 +1385,59 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, #endif && tls_lock_username(multi, up->username)) { - ks->authenticated = true; + ks->authenticated = KS_AUTH_TRUE; #ifdef PLUGIN_DEF_AUTH if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) { - ks->auth_deferred = true; + ks->authenticated = KS_AUTH_DEFERRED; } #endif #ifdef MANAGEMENT_DEF_AUTH if (man_def_auth != KMDA_UNDEF) { - ks->auth_deferred = true; + ks->authenticated = KS_AUTH_DEFERRED; } #endif + if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) + { + set_common_name(session, up->username); + } - if ((session->opt->auth_token_generate) && (NULL == multi->auth_token)) + if ((session->opt->auth_token_generate)) { - /* Server is configured with --auth-gen-token but no token has yet - * been generated for this client. Generate one and save it. + /* + * If we accepted a (not expired) token, i.e. + * initial auth via token on new connection, we need + * to store the auth-token in multi->auth_token, so + * the initial timestamp and session id can be extracted from it */ - uint8_t tok[AUTH_TOKEN_SIZE]; - - if (!rand_bytes(tok, AUTH_TOKEN_SIZE)) + if (!multi->auth_token + && (ks->auth_token_state_flags & AUTH_TOKEN_HMAC_OK) + && !(ks->auth_token_state_flags & AUTH_TOKEN_EXPIRED)) { - msg( M_FATAL, "Failed to get enough randomness for " - "authentication token"); + multi->auth_token = strdup(up->password); } - /* The token should be longer than the input when - * being base64 encoded + /* + * Server is configured with --auth-gen-token. Generate or renew + * the token. */ - ASSERT(openvpn_base64_encode(tok, AUTH_TOKEN_SIZE, - &multi->auth_token) > AUTH_TOKEN_SIZE); - multi->auth_token_tstamp = now; - dmsg(D_SHOW_KEYS, "Generated token for client: %s", - multi->auth_token); - } - - if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) - { - set_common_name(session, up->username); + generate_auth_token(up, multi); } - -#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", + (ks->authenticated == KS_AUTH_DEFERRED) ? "deferred" : "succeeded", up->username, (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); -#endif + if (ks->authenticated == KS_AUTH_TRUE) + { + ssl_session_fully_authenticated(multi, session); + } } else { + ks->authenticated = KS_AUTH_FALSE; msg(D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer"); } - -done: - gc_free(&gc); } void @@ -1477,7 +1452,7 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) } /* Don't allow the CN to change once it's been locked */ - if (ks->authenticated && 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)) @@ -1493,7 +1468,7 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) } /* Don't allow the cert hashes to change once they have been locked */ - if (ks->authenticated && 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)) @@ -1507,15 +1482,16 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) } /* verify --client-config-dir based authentication */ - if (ks->authenticated && session->opt->client_config_dir_exclusive) + if (ks->authenticated > KS_AUTH_FALSE && session->opt->client_config_dir_exclusive) { struct gc_arena gc = gc_new(); const char *cn = session->common_name; - const char *path = gen_path(session->opt->client_config_dir_exclusive, cn, &gc); - if (!cn || !strcmp(cn, CCD_DEFAULT) || !test_file(path)) + const char *path = platform_gen_path(session->opt->client_config_dir_exclusive, + cn, &gc); + if (!cn || !strcmp(cn, CCD_DEFAULT) || !platform_test_file(path)) { - ks->authenticated = false; + ks->authenticated = KS_AUTH_FALSE; wipe_auth_token(multi); msg(D_TLS_ERRORS, "TLS Auth Error: --client-config-dir authentication failed for common name '%s' file='%s'", session->common_name, @@ -1541,5 +1517,3 @@ tls_x509_clear_env(struct env_set *es) item = next; } } - -#endif /* ENABLE_CRYPTO */ |