New feature: --auth-gen-token
cover New feature: --auth-gen-token
This new feature enables re-authentication of on-going sessions without asking the user for a new password. This is in particular useful when the authentication scheme is based on One Time Passwords (OTP).
When OTP is used and without auth-token support in the authentication module OpenVPN is configured to use, the clients will be asked for a new OTP each time OpenVPN starts a re-negotiation. What often happens is that this re-negotiation is disabled to avoid this.
OpenVPN does provide a remedy to this, by pushing a unique auth-token value to each client. Then the authentication module needs to keep track of which client is using which auth-token value. When a client receives the pushed auth-token option and the attached value, it replaces the locally saved password with this token value. So for all coming re-authentications, the client will send this value as the password instead of the users password.
But not all authentication modules adds support for this feature. By adding --auth-gen-token to the server configuration, the OpenVPN server will take care of the auth-token processing and authentication. This also means that the server will not call the configured authentication module on re-negotiations; it will do the re-negotiation internally by itself.
This feature may just as well be useful for non-OTP configurations as well. Unless the OpenVPN client is configured with --auth-nocache, it will save the users password in-memory for the lifetime of the OpenVPN session. Using this feature that password will be replaced by the auth-token instead.
The patch-set this thread covers focuses only on this new --auth-gen-token feature. The --auth-token option added to OpenVPN 2.3, but never properly documented. The --auth-token documentation is tracked in this mail thread:
http://www.mail-archive.com/[email protected]/msg12506.html
(Message-Id: <http://www.mail-archive.com/[email protected]/msg12506.html>)
One remark regarding PATCH 1/5. This patch is needed by PATCH 5/5. I just chose to split it out as a separate patch to make the core auth-gen-token patches easier to review. This patch can be moved anywhere before PATCH 5/5 or squashed into PATCH 5/5 if that is requested.
David Sommerseth (5):
Move memcmp_constant_time() to crypto.h
auth-gen-token: Add --auth-gen-token option
auth-gen-token: Generate an auth-token per client
auth-gen-token: Push generated auth-tokens to the client
auth-gen-token: Authenticate generated auth-tokens when client
re-authenticates
doc/openvpn.8 | 16 ++++++++++ src/openvpn/crypto.c | 18 ----------- src/openvpn/crypto.h | 18 +++++++++++ src/openvpn/init.c | 2 ++ src/openvpn/misc.c | 5 +++ src/openvpn/options.c | 16 ++++++++++ src/openvpn/options.h | 2 ++ src/openvpn/push.c | 9 +++++- src/openvpn/ssl.c | 6 ++++ src/openvpn/ssl_common.h | 11 +++++++ src/openvpn/ssl_verify.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 167 insertions(+), 19 deletions(-)
Signature · 1 line
1.8.3.1
PATCH 1/5 Move memcmp_constant_time() to crypto.h
This function is quite useful other places, so make it generally accessible.
--- src/openvpn/crypto.c | 18 ------------------ src/openvpn/crypto.h | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-)
src/openvpn/crypto.c +0 -18
@@ -66,24 +66,6 @@#define CRYPT_ERROR (format) \ do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) -/** -* As memcmp(), but constant-time. -* Returns 0 when data is equal, non-zero otherwise. -*/ -static int -memcmp_constant_time (const void *a,const void *b,size_t size) { -const uint8_t * a1 = a; -const uint8_t * b1 = b; -int ret =0 ; -size_t i; - -for (i =0 ; i < size; i++) { - ret |= *a1++ ^ *b1++; - } - -return ret; -} -static void openvpn_encrypt_aead (struct buffer *buf,struct buffer work,struct crypto_options *opt) {
src/openvpn/crypto.h +18 -0
@@ -476,6 +476,24 @@ void get_tls_handshake_key (const struct key_type *key_type,* Inline functions */ +/** +* As memcmp(), but constant-time. +* Returns 0 when data is equal, non-zero otherwise. +*/ +static int +memcmp_constant_time (const void *a,const void *b,size_t size) { +const uint8_t * a1 = a; +const uint8_t * b1 = b; +int ret =0 ; +size_t i; + +for (i =0 ; i < size; i++) { + ret |= *a1++ ^ *b1++; + } + +return ret; +} +static inline bool key_ctx_bi_defined (const struct key_ctx_bi * key) {
Signature · 1 line
1.8.3.1
Re: [Openvpn-devel] [PATCH 1/5] Move memcmp_constant_time() to crypto.h
Hi David,
Quoted 43 lines · David Sommerseth
This function is quite useful other places, so make it generally accessible.
Signed-off-by David Sommerseth <[email protected]...>--- src/openvpn/crypto.c | 18 ------------------ src/openvpn/crypto.h | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-)src/openvpn/crypto.c +0
-18@@ -66,24 +66,6 @@#define CRYPT_ERROR (format) \ do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) -/** -* As memcmp(), but constant-time. -* Returns 0 when data is equal, non-zero otherwise. -*/ -static int -memcmp_constant_time (const void *a,const void *b,size_t size) { -const uint8_t * a1 = a; -const uint8_t * b1 = b; -int ret =0 ; -size_t i; - -for (i =0 ; i < size; i++) { - ret |= *a1++ ^ *b1++; - } - -return ret; -} -static void openvpn_encrypt_aead (struct buffer *buf,struct buffer work,struct crypto_options *opt) {src/openvpn/crypto.h +0
-0
src/openvpn/crypto.h void get_tls_handshake_key (const struct key_type *key_type, · line 483
Quoted 8 lines
src/openvpn/crypto.h +5
-0@@ -476,6 +476,24 @@ void get_tls_handshake_key (const struct key_type *key_type,* Inline functions */ +/** +* As memcmp(), but constant-time. +* Returns 0 when data is equal, non-zero otherwise. +*/ +static int
I think this should carry an 'inline', now that it's in the header.
src/openvpn/crypto.h void get_tls_handshake_key (const struct key_type *key_type, · line 490
Quoted 7 lines
src/openvpn/crypto.h +7
-0+memcmp_constant_time (const void *a, const void *b, size_t size) { + const uint8_t * a1 = a; +const uint8_t * b1 = b; +int ret =0 ; +size_t i; + +for (i =0 ; i < size; i++) {
Since we're allowed to write C99 now, can we take this opportunity to save ourselves a line and write for (size_t i = 0, ...) ? (Feel free to ignore if you disagree.)
If you fix the first comment: ACK.
-Steffan
Re: [Openvpn-devel] [PATCH 1/5] Move memcmp_constant_time() to crypto.h
Hi,
Quoted 7 lines · Steffan Karger
src/openvpn/crypto.h void get_tls_handshake_key (const struct key_type *key_type, · line 483
Quoted 5 lines
src/openvpn/crypto.h +5
-0+/** +* As memcmp(), but constant-time. +* Returns 0 when data is equal, non-zero otherwise. +*/ +static intI think this should carry an 'inline', now that it's in the header.
Indeed. Do not put non-inline static functions in headers - they can end up being compiled into every single compile unit that includes that particular header (*some* compilers are smart enough to see that it's static, and not referenced, but they are free to "not care") - and it's bad code anyway. Either inline, or non-inline "somewhere" and just the prototype goes into the header file.
gert
Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
//www.muc.de/~gert/
Gert Doering - Munich, Germany [email protected]...
fax: +49-89-35655025 [email protected]...Re: [Openvpn-devel] [PATCH applied] Move memcmp_constant_time() to crypto.h
In reply to David Sommerseth-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Your patch has been applied to the master branch
commit b891e57e1fe794483c08296e32c15751f2676a2d
Author: David Sommerseth Date: Thu Oct 13 21:59:27 2016 +0200
Move memcmp_constant_time() to crypto.h
Signed-off-by: David Sommerseth <[email protected]...>
Acked-by: Steffan Karger <[email protected]...>
Message-Id: <[email protected]...>
URL: https://www.mail-archive.com/[email protected]/msg12698.html- --
kind regards,
David Sommerseth
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)
iQIcBAEBAgAGBQJYAJvIAAoJEIbPlEyWcf3yX/AP/RJvvMzK/XdCwX+01FFhbZxQ DxjycWDUpCcbBgPQ7AwH2skxrZy9AS2xTvEaX2MhnpX8Adz4GF9Ny3nv6YnHmT++ b1BxVilyYJKO4L2fXKs1rifQS+KmDcMFBLCKsbnxkOUHEog/fp6kJFK44jkjqPMg o0H9ND+3EHTyV16RKPEW3K7qDcWO3f/eWmRZvwmDnizikoh7MWCFj1N+5Kznl/6O 7hjvsXBvunvKoiZLOLcM5gY/lqvVfQONN0vywGHPq+/FjNazlOPrvFlb2KGaCMQT llQnAxJAWi3jm5LmW2RZaPeky5VwLETBmwRxY4MXxqIQk2eCNYN7zEHyNf4V7jfC y3SPGMtmRuj6TASCfuoAxV4BJuWHJ3/ZNLuXEFdPF1InUWnTx4utxAklNFnTlA2l UFsePe+gkcr4ZqoT2B698Y00ElQwlTaJyabl6zvXuLMDFCvJXkms82i/S1oDbaqy KgzOMEFutjt1wlUHVD4+1/2Jpk8r7txvu26727uxoFlSKnJwKMa9ZEw0NNM8H4ry 5RyMouLyoVxquMTNAAUUwhLCFpZJADY/Qa3WzGe78ukOLxwPPY3kFyK5kJU6Ug9O Xdlead0n8qNBlX9gkDrlT8B0I2s3XCZ6tsB4GCM+UvGvYihvX0GQAX6u128pcgsx V1RpkCe78sai9KY2W0QQ
=0exT
-----END PGP SIGNATURE-----
Re: [Openvpn-devel] [PATCH applied] Move memcmp_constant_time() to crypto.h
Re: [Openvpn-devel] [PATCH applied] Move memcmp_constant_time() to crypto.h
In reply to David SommersethQuoted 6 lines · David Sommerseth
Your patch has been applied to the master branch
commit
b891e57e1fe794483c08296e32c15751f2676a2dAuthor: David Sommerseth Date: Thu Oct 13 21:59:27 2016 +0200
Quoted 7 lines
Move memcmp_constant_time() to crypto.h
Signed-off-by: David Sommerseth <[email protected]...>
Acked-by: Steffan Karger <[email protected]...>
Message-Id: <[email protected]...>
URL: https://www.mail-archive.com/[email protected]/msg12698.html[Lets try again, and see if Enigmail can be convinced not to encrypt it this time]
Just for reference, as I forgot to state that in the previous mail.
This patch was slightly modified at commit time. The function declaration changed from 'static int' to 'static inline int', as requested by Steffan Karger.
The difference is:
------------------------------------------------------------------------
@@ -31,7 +31,7 @@
+ * As memcmp(), but constant-time.
+ * Returns 0 when data is equal, non-zero otherwise.
+ */
-+static int
++static inline int
+memcmp_constant_time (const void *a, const void *b, size_t size) {
+ const uint8_t * a1 = a;
+ const uint8_t * b1 = b;
------------------------------------------------------------------------
Signature · 3 lines
kind regards, David Sommerseth
PATCH 2/5 auth-gen-token: Add --auth-gen-token option
In reply to David SommersethThis sets the flag if the OpenVPN server should create authentication tokens on-the-fly on successful --auth-user-pass-verify or --plugin with OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY processing.
If an OpenVPN server is running without this option, it should behave as before. Next patches will implement the auth-token generation and passing it on to the clients.
The --auth-gen-token can be given an optional integer argument which defines the lifetime of generated tokens. The lifetime argument must be given in number of seconds.
--- doc/openvpn.8 | 16 ++++++++++++++++ src/openvpn/init.c | 2 ++ src/openvpn/options.c | 16 ++++++++++++++++ src/openvpn/options.h | 2 ++ src/openvpn/ssl_common.h | 3 +++ 5 files changed, 39 insertions(+)
doc/openvpn.8 +16 -0
@@ -3595,6 +3595,22 @@ For a sample script that performs PAM authentication, see in the OpenVPN source distribution. .\"********************************************************* .TP +.B \-\-auth\-gen\-token [lifetime] +After successful user/password authentication, the OpenVPN +server will with this option generate a temporary +authentication token and push that to client. On the following +renegotiations, the OpenVPN client will pass this token instead +of the users password. On the server side the server will do +the token authentication internally and it will NOT do any +additional authentications against configured external +user/password authentication mechanisms. + +This feature is useful for environments which is configured +to use One Time Passwords (OTP) as part of the user/password +authentications and that authentication mechanism does not +implement any auth-token support. +.\"********************************************************* +.TP .B \-\-opt\-verify Clients that connect with options that are incompatible with those of the server will be disconnected.
src/openvpn/init.c +2 -0
@@ -2427,6 +2427,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)if (options->ccd_exclusive) to.client_config_dir_exclusive = options->client_config_dir; to.auth_user_pass_file = options->auth_user_pass_file; + to.auth_generate_token = options->auth_generate_token; + to.auth_token_lifetime = options->auth_token_lifetime;#endif to.x509_track = options->x509_track;
src/openvpn/options.c +16 -0
@@ -445,6 +445,11 @@ static const char usage_message[] =" run command cmd to verify. If method='via-env', pass\n" " user/pass via environment, if method='via-file', pass\n" " user/pass via temporary file.\n" +"--auth-gen-token [lifetime] Generate a random authentication token which is pushed\n" +" to each client, replacing the password. Usefull when\n" +" OTP based two-factor auth mechanisms are in use and\n" +" --reneg-* options are enabled. Optionally a lifetime in seconds\n" +" for generated tokens can be set.\n" "--opt-verify : Clients that connect with options that are incompatible\n" " with those of the server will be disconnected.\n" "--auth-user-pass-optional : Allow connections by clients that don't\n"
@@ -864,6 +869,7 @@ init_options (struct options *o, const bool init_gc)#ifdef ENABLE_PKCS11 o->pkcs11_pin_cache_period =-1 ;#endif /* ENABLE_PKCS11 */ + o->auth_generate_token = false;/* tmp is only used in P2MP server context */ #if P2MP_SERVER
@@ -1264,6 +1270,8 @@ show_p2mp_parms (const struct options *o)SHOW_INT (max_routes_per_client);SHOW_STR (auth_user_pass_verify_script);SHOW_BOOL (auth_user_pass_verify_script_via_file); +SHOW_BOOL (auth_generate_token); +SHOW_INT (auth_token_lifetime);#if PORT_SHARE SHOW_STR (port_share_host);SHOW_STR (port_share_port);
@@ -2194,6 +2202,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne "tcp-nodelay in the server configuration instead.");if (options->auth_user_pass_verify_script)msg (M_USAGE ,"--auth-user-pass-verify requires --mode server" ); +if (options->auth_generate_token) +msg (M_USAGE ,"--auth-gen-token requires --mode server" );#if PORT_SHARE if (options->port_share_host || options->port_share_port)msg (M_USAGE ,"--port-share requires TCP server mode (--mode server --proto tcp-server)" );
@@ -5973,6 +5983,12 @@ add_option (struct options *options, &options->auth_user_pass_verify_script, p[1], "auth-user-pass-verify", true); } +else if (streq (p[0 ],"auth-gen-token" )) + { +VERIFY_PERMISSION (OPT_P_GENERAL ); + options->auth_generate_token = true; + options->auth_token_lifetime = p[1 ] ?positive_atoi (p[1 ]) :0 ; + }else if (streq (p[0 ],"client-connect" ) && p[1 ]) {VERIFY_PERMISSION (OPT_P_SCRIPT );
src/openvpn/options.h +2 -0
@@ -443,6 +443,8 @@ struct optionsconst char *auth_user_pass_verify_script;bool auth_user_pass_verify_script_via_file; +bool auth_generate_token; +unsigned int auth_token_lifetime;#if PORT_SHARE char *port_share_host;char *port_share_port;
src/openvpn/ssl_common.h +3 -0
@@ -289,6 +289,9 @@ struct tls_optionsbool auth_user_pass_verify_script_via_file;const char *tmp_dir;const char *auth_user_pass_file; +bool auth_generate_token;/**< Generate auth-tokens on successful user/pass auth, +* set via options->auth_generate_token. */ +unsigned int auth_token_lifetime;/* use the client-config-dir as a positive authenticator */ const char *client_config_dir_exclusive;
Signature · 1 line
1.8.3.1
Re: [Openvpn-devel] [PATCH 2/5] auth-gen-token: Add --auth-gen-token option
Quoted 28 lines · David Sommerseth
This sets the flag if the OpenVPN server should create authentication tokens on-the-fly on successful --auth-user-pass-verify or --plugin with
OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFYprocessing.If an OpenVPN server is running without this option, it should behave as before. Next patches will implement the auth-token generation and passing it on to the clients.
The --auth-gen-token can be given an optional integer argument which defines the lifetime of generated tokens. The lifetime argument must be given in number of seconds.
Signed-off-by David Sommerseth <[email protected]...>--- doc/openvpn.8 | 16 ++++++++++++++++ src/openvpn/init.c | 2 ++ src/openvpn/options.c | 16 ++++++++++++++++ src/openvpn/options.h | 2 ++ src/openvpn/ssl_common.h | 3 +++ 5 files changed, 39 insertions(+)doc/openvpn.8 +0
-0@@ -3595,6 +3595,22 @@ For a sample script that performs PAM authentication, see in the OpenVPN source distribution. .\"*********************************************************
doc/openvpn.8 For a sample script that performs PAM authentication, see · line 3606
Quoted 10 lines
doc/openvpn.8 +9
-0.TP +.B \-\-auth\-gen\-token [lifetime] +After successful user/password authentication, the OpenVPN +server will with this option generate a temporary +authentication token and push that to client. On the following +renegotiations, the OpenVPN client will pass this token instead +of the users password. On the server side the server will do +the token authentication internally and it will NOT do any +additional authentications against configured external +user/password authentication mechanisms.
This should mention that a lifetime of 0 indicates 'never expires'.
Quoted 82 lines
doc/openvpn.8 +6
-0+This feature is useful for environments which is configured +to use One Time Passwords (OTP) as part of the user/password +authentications and that authentication mechanism does not +implement any auth-token support. +.\"********************************************************* +.TP .B \-\-opt\-verify Clients that connect with options that are incompatible with those of the server will be disconnected.src/openvpn/init.c +2
-0@@ -2427,6 +2427,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)if (options->ccd_exclusive) to.client_config_dir_exclusive = options->client_config_dir; to.auth_user_pass_file = options->auth_user_pass_file; + to.auth_generate_token = options->auth_generate_token; + to.auth_token_lifetime = options->auth_token_lifetime;#endif to.x509_track = options->x509_track;src/openvpn/options.c +16
-0@@ -445,6 +445,11 @@ static const char usage_message[] =" run command cmd to verify. If method='via-env', pass\n" " user/pass via environment, if method='via-file', pass\n" " user/pass via temporary file.\n" +"--auth-gen-token [lifetime] Generate a random authentication token which is pushed\n" +" to each client, replacing the password. Usefull when\n" +" OTP based two-factor auth mechanisms are in use and\n" +" --reneg-* options are enabled. Optionally a lifetime in seconds\n" +" for generated tokens can be set.\n" "--opt-verify : Clients that connect with options that are incompatible\n" " with those of the server will be disconnected.\n" "--auth-user-pass-optional : Allow connections by clients that don't\n" @@ -864,6 +869,7 @@ init_options (struct options *o, const bool init_gc)#ifdef ENABLE_PKCS11 o->pkcs11_pin_cache_period =-1 ;#endif /* ENABLE_PKCS11 */ + o->auth_generate_token = false;/* tmp is only used in P2MP server context */ #if P2MP_SERVER @@ -1264,6 +1270,8 @@ show_p2mp_parms (const struct options *o)SHOW_INT (max_routes_per_client);SHOW_STR (auth_user_pass_verify_script);SHOW_BOOL (auth_user_pass_verify_script_via_file); +SHOW_BOOL (auth_generate_token); +SHOW_INT (auth_token_lifetime);#if PORT_SHARE SHOW_STR (port_share_host);SHOW_STR (port_share_port);@@ -2194,6 +2202,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne "tcp-nodelay in the server configuration instead.");if (options->auth_user_pass_verify_script)msg (M_USAGE ,"--auth-user-pass-verify requires --mode server" ); +if (options->auth_generate_token) +msg (M_USAGE ,"--auth-gen-token requires --mode server" );#if PORT_SHARE if (options->port_share_host || options->port_share_port)msg (M_USAGE ,"--port-share requires TCP server mode (--mode server --proto tcp-server)" );@@ -5973,6 +5983,12 @@ add_option (struct options *options, &options->auth_user_pass_verify_script, p[1], "auth-user-pass-verify", true); } +else if (streq (p[0 ],"auth-gen-token" )) + { +VERIFY_PERMISSION (OPT_P_GENERAL ); + options->auth_generate_token = true; + options->auth_token_lifetime = p[1 ] ?positive_atoi (p[1 ]) :0 ; + }else if (streq (p[0 ],"client-connect" ) && p[1 ]) {VERIFY_PERMISSION (OPT_P_SCRIPT );src/openvpn/options.h +0
-0
src/openvpn/options.h struct options · line 447
Quoted 5 lines
src/openvpn/options.h +2
-0@@ -443,6 +443,8 @@ struct optionsconst char *auth_user_pass_verify_script;bool auth_user_pass_verify_script_via_file; +bool auth_generate_token; +unsigned int auth_token_lifetime;
Since we're discussing naming stuff on IRC now anyway, I'd suggest to give these strongly related variables a common auth_token_* prefix, e.g. auth_token_generate and auth_token_lifetime.
Quoted 8 lines
src/openvpn/options.h +0
-0#if PORT_SHARE char *port_share_host;char *port_share_port;src/openvpn/ssl_common.h +0
-0
src/openvpn/ssl_common.h struct tls_options · line 294
Quoted 6 lines
src/openvpn/ssl_common.h +3
-0@@ -289,6 +289,9 @@ struct tls_optionsbool auth_user_pass_verify_script_via_file;const char *tmp_dir;const char *auth_user_pass_file; +bool auth_generate_token;/**< Generate auth-tokens on successful user/pass auth, +* set via options->auth_generate_token. */ +unsigned int auth_token_lifetime;
Same as above :)
Other than that, patch looks good. I do think it shouldn't be applied until 3/5 to 5/5 are ready to be applied too.
-Steffan
PATCH 1/1 auth-gen-token: Add --auth-gen-token option
In reply to David SommersethThis sets the flag if the OpenVPN server should create authentication tokens on-the-fly on successful --auth-user-pass-verify or --plugin with OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY processing.
If an OpenVPN server is running without this option, it should behave as before. Next patches will implement the auth-token generation and passing it on to the clients.
The --auth-gen-token can be given an optional integer argument which defines the lifetime of generated tokens. The lifetime argument must be given in number of seconds.
v2 - Update Changes.rst
- Improve man page in regards to lifetime argument
- Rename struct member auth_generate_token to auth_token_generate to have a consistent naming scheme
--- Changes.rst | 15 +++++++++++++++ doc/openvpn.8 | 22 ++++++++++++++++++++++ src/openvpn/init.c | 2 ++ src/openvpn/options.c | 16 ++++++++++++++++ src/openvpn/options.h | 2 ++ src/openvpn/ssl_common.h | 3 +++ 6 files changed, 60 insertions(+)
Changes.rst +15 -0
@@ -62,6 +62,21 @@ Cipher negotiation to use that cipher. Data channel cipher negotiation can be controlled using --ncp-ciphers and --ncp-disable. +Authentication tokens + In situations where it is not suitable to save users passwords on the client + OpenVPN have since v2.3 had support for --auth-token. This option is + pushed from the server to the client with a token value to be used instead + of the users password. For this to work, the authentication plug-in would + need to implement this support as well. In OpenVPN 2.4 --auth-gen-token + is introduced, which will allow the OpenVPN server to generate a random + token and push it to the client without any changes to the authentication + modules. When the clients need to re-authenticate the OpenVPN server will + instead of sending the re-authentication request to the authentication + module do the authentication internally. This feature is especially + useful in configurations which adds One Time Password (OTP) authentication + schemes, as this allows the tunnel to be renegotiated regularly without + any need to supply new OTP codes. + User-visible Changes --------------------
doc/openvpn.8 +22 -0
@@ -3595,6 +3595,28 @@ For a sample script that performs PAM authentication, see in the OpenVPN source distribution. .\"********************************************************* .TP +.B \-\-auth\-gen\-token [lifetime] +After successful user/password authentication, the OpenVPN +server will with this option generate a temporary +authentication token and push that to client. On the following +renegotiations, the OpenVPN client will pass this token instead +of the users password. On the server side the server will do +the token authentication internally and it will NOT do any +additional authentications against configured external +user/password authentication mechanisms. + +The +.B lifetime +argument defines how long the generated token is valid. The +lifetime is defined in seconds. If lifetime is not set +or it is set to 0, the token will never expire. + +This feature is useful for environments which is configured +to use One Time Passwords (OTP) as part of the user/password +authentications and that authentication mechanism does not +implement any auth-token support. +.\"********************************************************* +.TP .B \-\-opt\-verify Clients that connect with options that are incompatible with those of the server will be disconnected.
src/openvpn/init.c +2 -0
@@ -2427,6 +2427,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)if (options->ccd_exclusive) to.client_config_dir_exclusive = options->client_config_dir; to.auth_user_pass_file = options->auth_user_pass_file; + to.auth_token_generate = options->auth_token_generate; + to.auth_token_lifetime = options->auth_token_lifetime;#endif to.x509_track = options->x509_track;
src/openvpn/options.c +16 -0
@@ -445,6 +445,11 @@ static const char usage_message[] =" run command cmd to verify. If method='via-env', pass\n" " user/pass via environment, if method='via-file', pass\n" " user/pass via temporary file.\n" +"--auth-gen-token [lifetime] Generate a random authentication token which is pushed\n" +" to each client, replacing the password. Usefull when\n" +" OTP based two-factor auth mechanisms are in use and\n" +" --reneg-* options are enabled. Optionally a lifetime in seconds\n" +" for generated tokens can be set.\n" "--opt-verify : Clients that connect with options that are incompatible\n" " with those of the server will be disconnected.\n" "--auth-user-pass-optional : Allow connections by clients that don't\n"
@@ -864,6 +869,7 @@ init_options (struct options *o, const bool init_gc)#ifdef ENABLE_PKCS11 o->pkcs11_pin_cache_period =-1 ;#endif /* ENABLE_PKCS11 */ + o->auth_token_generate = false;/* tmp is only used in P2MP server context */ #if P2MP_SERVER
@@ -1264,6 +1270,8 @@ show_p2mp_parms (const struct options *o)SHOW_INT (max_routes_per_client);SHOW_STR (auth_user_pass_verify_script);SHOW_BOOL (auth_user_pass_verify_script_via_file); +SHOW_BOOL (auth_token_generate); +SHOW_INT (auth_token_lifetime);#if PORT_SHARE SHOW_STR (port_share_host);SHOW_STR (port_share_port);
@@ -2194,6 +2202,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne "tcp-nodelay in the server configuration instead.");if (options->auth_user_pass_verify_script)msg (M_USAGE ,"--auth-user-pass-verify requires --mode server" ); +if (options->auth_token_generate) +msg (M_USAGE ,"--auth-gen-token requires --mode server" );#if PORT_SHARE if (options->port_share_host || options->port_share_port)msg (M_USAGE ,"--port-share requires TCP server mode (--mode server --proto tcp-server)" );
@@ -5973,6 +5983,12 @@ add_option (struct options *options, &options->auth_user_pass_verify_script, p[1], "auth-user-pass-verify", true); } +else if (streq (p[0 ],"auth-gen-token" )) + { +VERIFY_PERMISSION (OPT_P_GENERAL ); + options->auth_token_generate = true; + options->auth_token_lifetime = p[1 ] ?positive_atoi (p[1 ]) :0 ; + }else if (streq (p[0 ],"client-connect" ) && p[1 ]) {VERIFY_PERMISSION (OPT_P_SCRIPT );
src/openvpn/options.h +2 -0
@@ -443,6 +443,8 @@ struct optionsconst char *auth_user_pass_verify_script;bool auth_user_pass_verify_script_via_file; +bool auth_token_generate; +unsigned int auth_token_lifetime;#if PORT_SHARE char *port_share_host;char *port_share_port;
src/openvpn/ssl_common.h +3 -0
@@ -289,6 +289,9 @@ struct tls_optionsbool auth_user_pass_verify_script_via_file;const char *tmp_dir;const char *auth_user_pass_file; +bool auth_token_generate;/**< Generate auth-tokens on successful user/pass auth, +* set via options->auth_token_generate. */ +unsigned int auth_token_lifetime;/* use the client-config-dir as a positive authenticator */ const char *client_config_dir_exclusive;
Signature · 1 line
1.8.3.1
PATCH 3/5 auth-gen-token: Generate an auth-token per client
In reply to David SommersethWhen --auth-gen-token is used a random token key is generated for each client after a successful user/password authentication. This token is expected to be returned in the password field on the following authentications.
The token is 256 bits long and BASE64 encoded before it is stored.
--- src/openvpn/ssl.c | 6 ++++++ src/openvpn/ssl_common.h | 6 ++++++ src/openvpn/ssl_verify.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+)
src/openvpn/ssl.c +6 -0
@@ -1173,6 +1173,12 @@ tls_multi_free (struct tls_multi *multi, bool clear)cert_hash_free (multi->locked_cert_hash_set); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + } +for (i =0 ; i <TM_SIZE ; ++i)tls_session_free (&multi->session[i], false);
src/openvpn/ssl_common.h +6 -0
@@ -351,6 +351,7 @@ struct tls_options/** @} name Index of key_state objects within a tls_session structure */ /** @} addtogroup control_processor */ +#define AUTH_TOKEN_SIZE 32/**< Size of server side generated auth tokens. 32 bytes == 256 bits */ /** * Security parameter state of a single session within a VPN tunnel.
@@ -525,6 +526,11 @@ struct tls_multiuint32_t peer_id;bool use_peer_id; +char *auth_token;/** If server sends a generated auth-token, +* this is the token to use for future +* user/pass authentications in this session. +*/ +time_t auth_token_tstamp;/**< timestamp of the generated token */ /* * Our session objects. */
src/openvpn/ssl_verify.c +33 -0
@@ -39,6 +39,8 @@#include "misc.h" #include "manage.h" +#include "otime.h" +#include "base64.h" #include "ssl_verify.h" #include "ssl_verify_backend.h"
@@ -1174,6 +1176,37 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,if (man_def_auth !=KMDA_UNDEF ) ks->auth_deferred = true;#endif + +if ((session->opt->auth_generate_token) && (NULL == multi->auth_token)) + { +/* Server is configured with --auth-gen-token but no token has yet been +* generated for this client. Generate one and save it. +*/ +uint8_t tok[AUTH_TOKEN_SIZE ]; + +if (!rand_bytes (tok,AUTH_TOKEN_SIZE )) + { +msg (M_FATAL ,"Failed to get enough randomness for authentication token" ); + } + +/* The token should be longer than the input when being base64 encoded*/ +if (openvpn_base64_encode (tok,AUTH_TOKEN_SIZE , &multi->auth_token) <AUTH_TOKEN_SIZE ) + { +msg (D_TLS_ERRORS ,"BASE64 encoding of token failed. No auth-token will be activated now" ); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + multi->auth_token =NULL ; + } + } +else + { + 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);#ifdef ENABLE_DEF_AUTH
Signature · 1 line
1.8.3.1
Re: [Openvpn-devel] [PATCH 3/5] auth-gen-token: Generate an auth-token per client
Hi,
Patch looks good, but haven't tested yet. Will test he set as a whole.
Some minor remarks:
Quoted 19 lines · David Sommerseth
When --auth-gen-token is used a random token key is generated for each client after a successful user/password authentication. This token is expected to be returned in the password field on the following authentications.
The token is 256 bits long and BASE64 encoded before it is stored.
Signed-off-by David Sommerseth <[email protected]...>--- src/openvpn/ssl.c | 6 ++++++ src/openvpn/ssl_common.h | 6 ++++++ src/openvpn/ssl_verify.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+)src/openvpn/ssl.c +0
-0
src/openvpn/ssl.c tls_multi_free (struct tls_multi *multi, bool clear) · line 1180
Quoted 8 lines
src/openvpn/ssl.c +5
-0@@ -1173,6 +1173,12 @@ tls_multi_free (struct tls_multi *multi, bool clear)cert_hash_free (multi->locked_cert_hash_set); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + }
This memset() is likely to be optimized away by the compiler, but we have many more like this, so let's leave it like this for now, and fix all these in one go (I created trac #751 to keep track).
Quoted 16 lines
src/openvpn/ssl.c +0
-0for (i =0 ; i <TM_SIZE ; ++i)tls_session_free (&multi->session[i], false);src/openvpn/ssl_common.h +1
-0@@ -351,6 +351,7 @@ struct tls_options/** @} name Index of key_state objects within a tls_session structure */ /** @} addtogroup control_processor */ +#define AUTH_TOKEN_SIZE 32/**< Size of server side generated auth tokens. 32 bytes == 256 bits */ /** * Security parameter state of a single session within a VPN tunnel.
src/openvpn/ssl_common.h struct tls_multi · line 532
Quoted 7 lines
src/openvpn/ssl_common.h +4
-0@@ -525,6 +526,11 @@ struct tls_multiuint32_t peer_id;bool use_peer_id; +char *auth_token;/** If server sends a generated auth-token, +* this is the token to use for future +* user/pass authentications in this session. +*/
Use /**< to make this a doxygen comment (like you did below).
Quoted 28 lines
src/openvpn/ssl_common.h +1
-0+time_t auth_token_tstamp;/**< timestamp of the generated token */ /* * Our session objects. */ src/openvpn/ssl_verify.c +9
-0@@ -39,6 +39,8 @@#include "misc.h" #include "manage.h" +#include "otime.h" +#include "base64.h" #include "ssl_verify.h" #include "ssl_verify_backend.h" @@ -1174,6 +1176,37 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,if (man_def_auth !=KMDA_UNDEF ) ks->auth_deferred = true;#endif + +if ((session->opt->auth_generate_token) && (NULL == multi->auth_token)) + { +/* Server is configured with --auth-gen-token but no token has yet been +* generated for this client. Generate one and save it. +*/ +uint8_t tok[AUTH_TOKEN_SIZE ];
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1195
Quoted 10 lines
src/openvpn/ssl_verify.c +10
-0+ +if (!rand_bytes (tok,AUTH_TOKEN_SIZE )) + { +msg (M_FATAL ,"Failed to get enough randomness for authentication token" ); + } + +/* The token should be longer than the input when being base64 encoded*/ +if (openvpn_base64_encode (tok,AUTH_TOKEN_SIZE , &multi->auth_token) <AUTH_TOKEN_SIZE ) + { +msg (D_TLS_ERRORS ,"BASE64 encoding of token failed. No auth-token will be activated now" );
These are quite a bit longer than 80 chars.
-Steffan
PATCH v2 3/5 auth-gen-token: Generate an auth-token per client
In reply to David SommersethWhen --auth-gen-token is used a random token key is generated for each client after a successful user/password authentication. This token is expected to be returned in the password field on the following authentications.
The token is 256 bits long and BASE64 encoded before it is stored.
v2 - Fix Doxygen comment typo
- Don't exceed 80 chars line length
--- src/openvpn/ssl.c | 6 ++++++ src/openvpn/ssl_common.h | 8 ++++++++ src/openvpn/ssl_verify.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+)
src/openvpn/ssl.c +6 -0
@@ -1173,6 +1173,12 @@ tls_multi_free (struct tls_multi *multi, bool clear)cert_hash_free (multi->locked_cert_hash_set); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + } +for (i =0 ; i <TM_SIZE ; ++i)tls_session_free (&multi->session[i], false);
src/openvpn/ssl_common.h +8 -0
@@ -351,6 +351,7 @@ struct tls_options/** @} name Index of key_state objects within a tls_session structure */ /** @} addtogroup control_processor */ +#define AUTH_TOKEN_SIZE 32/**< Size of server side generated auth tokens. 32 bytes == 256 bits */ /** * Security parameter state of a single session within a VPN tunnel.
@@ -525,6 +526,13 @@ struct tls_multiuint32_t peer_id;bool use_peer_id; +bool auth_token_sent;/**< If server uses --auth-gen-token and +* token has been sent to client */ +char *auth_token;/**< If server sends a generated auth-token, +* this is the token to use for future +* user/pass authentications in this session. +*/ +time_t auth_token_tstamp;/**< timestamp of the generated token */ /* * Our session objects. */
src/openvpn/ssl_verify.c +39 -0
@@ -39,6 +39,8 @@#include "misc.h" #include "manage.h" +#include "otime.h" +#include "base64.h" #include "ssl_verify.h" #include "ssl_verify_backend.h"
@@ -1174,6 +1176,43 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,if (man_def_auth !=KMDA_UNDEF ) ks->auth_deferred = true;#endif + +if ((session->opt->auth_generate_token) && (NULL == multi->auth_token)) + { +/* Server is configured with --auth-gen-token but no token has yet +* been generated for this client. Generate one and save it. +*/ +uint8_t tok[AUTH_TOKEN_SIZE ]; + +if (!rand_bytes (tok,AUTH_TOKEN_SIZE )) + { +msg (M_FATAL ,"Failed to get enough randomness for " +"authentication token" ); + } + +/* The token should be longer than the input when +* being base64 encoded +*/ +if (openvpn_base64_encode (tok,AUTH_TOKEN_SIZE , + &multi->auth_token) <AUTH_TOKEN_SIZE ) + { +msg (D_TLS_ERRORS ,"BASE64 encoding of token failed. " +"No auth-token will be activated now" ); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + multi->auth_token =NULL ; + } + } +else + { + 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);#ifdef ENABLE_DEF_AUTH
Signature · 1 line
1.8.3.1
Re: [Openvpn-devel] [PATCH v2 3/5] auth-gen-token: Generate an auth-token per client
Re: [Openvpn-devel] [PATCH v2 3/5] auth-gen-token: Generate an auth-token per client
In reply to David SommersethMeh ... disregard this patch. Just noticed that the auth_token_sent member in the struct tls_options sneaked into this patch during my git rebasing.
I'll send the correct v2 patch (as v2.1 in the subject only)
--
kind regards,
David Sommerseth
Quoted 118 lines · David Sommerseth
When --auth-gen-token is used a random token key is generated for each client after a successful user/password authentication. This token is expected to be returned in the password field on the following authentications.
The token is 256 bits long and BASE64 encoded before it is stored.
v2 - Fix Doxygen comment typo
- Don't exceed 80 chars line lengthSigned-off-by David Sommerseth <[email protected]...>--- src/openvpn/ssl.c | 6 ++++++ src/openvpn/ssl_common.h | 8 ++++++++ src/openvpn/ssl_verify.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+)src/openvpn/ssl.c +6
-0@@ -1173,6 +1173,12 @@ tls_multi_free (struct tls_multi *multi, bool clear)cert_hash_free (multi->locked_cert_hash_set); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + } +for (i =0 ; i <TM_SIZE ; ++i)tls_session_free (&multi->session[i], false);src/openvpn/ssl_common.h +8
-0@@ -351,6 +351,7 @@ struct tls_options/** @} name Index of key_state objects within a tls_session structure */ /** @} addtogroup control_processor */ +#define AUTH_TOKEN_SIZE 32/**< Size of server side generated auth tokens. 32 bytes == 256 bits */ /** * Security parameter state of a single session within a VPN tunnel. @@ -525,6 +526,13 @@ struct tls_multiuint32_t peer_id;bool use_peer_id; +bool auth_token_sent;/**< If server uses --auth-gen-token and +* token has been sent to client */ +char *auth_token;/**< If server sends a generated auth-token, +* this is the token to use for future +* user/pass authentications in this session. +*/ +time_t auth_token_tstamp;/**< timestamp of the generated token */ /* * Our session objects. */ src/openvpn/ssl_verify.c +39
-0@@ -39,6 +39,8 @@#include "misc.h" #include "manage.h" +#include "otime.h" +#include "base64.h" #include "ssl_verify.h" #include "ssl_verify_backend.h" @@ -1174,6 +1176,43 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,if (man_def_auth !=KMDA_UNDEF ) ks->auth_deferred = true;#endif + +if ((session->opt->auth_generate_token) && (NULL == multi->auth_token)) + { +/* Server is configured with --auth-gen-token but no token has yet +* been generated for this client. Generate one and save it. +*/ +uint8_t tok[AUTH_TOKEN_SIZE ]; + +if (!rand_bytes (tok,AUTH_TOKEN_SIZE )) + { +msg (M_FATAL ,"Failed to get enough randomness for " +"authentication token" ); + } + +/* The token should be longer than the input when +* being base64 encoded +*/ +if (openvpn_base64_encode (tok,AUTH_TOKEN_SIZE , + &multi->auth_token) <AUTH_TOKEN_SIZE ) + { +msg (D_TLS_ERRORS ,"BASE64 encoding of token failed. " +"No auth-token will be activated now" ); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + multi->auth_token =NULL ; + } + } +else + { + 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);#ifdef ENABLE_DEF_AUTH
Signature · 3 lines
kind regards, David Sommerseth
PATCH 3/5 auth-gen-token: Generate an auth-token per client
In reply to David SommersethWhen --auth-gen-token is used a random token key is generated for each client after a successful user/password authentication. This token is expected to be returned in the password field on the following authentications.
The token is 256 bits long and BASE64 encoded before it is stored.
v2 - Fix Doxygen comment typo
- Don't exceed 80 chars line length
--- src/openvpn/ssl.c | 6 ++++++ src/openvpn/ssl_common.h | 8 ++++++++ src/openvpn/ssl_verify.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+)
src/openvpn/ssl.c +6 -0
@@ -1173,6 +1173,12 @@ tls_multi_free (struct tls_multi *multi, bool clear)cert_hash_free (multi->locked_cert_hash_set); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + } +for (i =0 ; i <TM_SIZE ; ++i)tls_session_free (&multi->session[i], false);
src/openvpn/ssl_common.h +8 -0
@@ -351,6 +351,9 @@ struct tls_options/** @} name Index of key_state objects within a tls_session structure */ /** @} addtogroup control_processor */ +#define AUTH_TOKEN_SIZE 32/**< Size of server side generated auth tokens. +* 32 bytes == 256 bits +*/ /** * Security parameter state of a single session within a VPN tunnel.
@@ -525,6 +528,11 @@ struct tls_multiuint32_t peer_id;bool use_peer_id; +char *auth_token;/**< If server sends a generated auth-token, +* this is the token to use for future +* user/pass authentications in this session. +*/ +time_t auth_token_tstamp;/**< timestamp of the generated token */ /* * Our session objects. */
src/openvpn/ssl_verify.c +39 -0
@@ -39,6 +39,8 @@#include "misc.h" #include "manage.h" +#include "otime.h" +#include "base64.h" #include "ssl_verify.h" #include "ssl_verify_backend.h"
@@ -1174,6 +1176,43 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,if (man_def_auth !=KMDA_UNDEF ) ks->auth_deferred = true;#endif + +if ((session->opt->auth_token_generate) && (NULL == multi->auth_token)) + { +/* Server is configured with --auth-gen-token but no token has yet +* been generated for this client. Generate one and save it. +*/ +uint8_t tok[AUTH_TOKEN_SIZE ]; + +if (!rand_bytes (tok,AUTH_TOKEN_SIZE )) + { +msg (M_FATAL ,"Failed to get enough randomness for " +"authentication token" ); + } + +/* The token should be longer than the input when +* being base64 encoded +*/ +if (openvpn_base64_encode (tok,AUTH_TOKEN_SIZE , + &multi->auth_token) <AUTH_TOKEN_SIZE ) + { +msg (D_TLS_ERRORS ,"BASE64 encoding of token failed. " +"No auth-token will be activated now" ); +if (multi->auth_token) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + multi->auth_token =NULL ; + } + } +else + { + 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);#ifdef ENABLE_DEF_AUTH
Signature · 1 line
1.8.3.1
PATCH 4/5 auth-gen-token: Push generated auth-tokens to the client
In reply to David SommersethIf --auth-gen-token has been enabled and a token has been generated, ensure this token is pushed to the client using the 'auth-token' option.
--- src/openvpn/misc.c | 5 +++++ src/openvpn/push.c | 9 ++++++++- src/openvpn/ssl_common.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-)
src/openvpn/misc.c +5 -0
@@ -2073,6 +2073,11 @@ sanitize_control_message(const char *src, struct gc_arena *gc) skip =4 ; redact = true; } +else if (!check_debug_level (D_SHOW_KEYS ) && (c =='a' && !strncmp (src,"auth-token " ,11 ))) + { + skip =10 ; + redact = true; + }if (c ==',' )/* end of redacted item? */ {
src/openvpn/push.c +8 -1
@@ -309,7 +309,7 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, struct push_list *push_list) {const char *optstr =NULL ; -const struct tls_multi *tls_multi = c->c2.tls_multi; +struct tls_multi *tls_multi = c->c2.tls_multi;const char *const peer_info = tls_multi->peer_info;struct options *o = &c->options;
@@ -371,6 +371,13 @@ prepare_push_reply (struct context *c, struct gc_arena *gc,push_option_fmt (gc, push_list,M_USAGE ,"cipher %s" , o->ciphername); } } + +/* If server uses --auth-gen-token and we have an auth token to send to client */ +if (false == tls_multi->auth_token_sent &&NULL != tls_multi->auth_token) + { +push_option_fmt (gc, push_list,M_USAGE ,"auth-token %s" , tls_multi->auth_token); + tls_multi->auth_token_sent = true; + }return true; }
src/openvpn/ssl_common.h +2 -0
@@ -526,6 +526,8 @@ struct tls_multiuint32_t peer_id;bool use_peer_id; +bool auth_token_sent;/**< If server uses --auth-gen-token and +* token has been sent to client */ char *auth_token;/** If server sends a generated auth-token, * this is the token to use for future * user/pass authentications in this session.
Signature · 1 line
1.8.3.1
Re: [Openvpn-devel] [PATCH 4/5] auth-gen-token: Push generated auth-tokens to the client
Quoted 15 lines · David Sommerseth
If --auth-gen-token has been enabled and a token has been generated, ensure this token is pushed to the client using the 'auth-token' option.
Signed-off-by David Sommerseth <[email protected]...>--- src/openvpn/misc.c | 5 +++++ src/openvpn/push.c | 9 ++++++++- src/openvpn/ssl_common.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-)src/openvpn/misc.c +0
-0
src/openvpn/misc.c sanitize_control_message(const char *src, struct gc_arena *gc) · line 2080
Quoted 8 lines
src/openvpn/misc.c +5
-0@@ -2073,6 +2073,11 @@ sanitize_control_message(const char *src, struct gc_arena *gc) skip =4 ; redact = true; } +else if (!check_debug_level (D_SHOW_KEYS ) && (c =='a' && !strncmp (src,"auth-token " ,11 ))) + { + skip =10 ; + redact = true; + }
This magic here should probably be explained in the commit message. It basically removes the auth-token value from the log file, unless --verb is set to 7 or higher and debug logging have not been disabled (configure --disable-debug).
Signature · 3 lines
kind regards, David Sommerseth
Re: [Openvpn-devel] [PATCH 4/5] auth-gen-token: Push generated auth-tokens to the client
In reply to David Sommersethsrc/openvpn/misc.c sanitize_control_message(const char *src, struct gc_arena *gc)
Quoted 15 lines · David Sommerseth
If --auth-gen-token has been enabled and a token has been generated, ensure this token is pushed to the client using the 'auth-token' option.
Signed-off-by David Sommerseth <[email protected]...>--- src/openvpn/misc.c | 5 +++++ src/openvpn/push.c | 9 ++++++++- src/openvpn/ssl_common.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-)src/openvpn/misc.c +0
-0@@ -2073,6 +2073,11 @@ sanitize_control_message(const char *src, struct gc_arena *gc)
Wait, what? We have over 2000 lines of 'misc.c'...?
src/openvpn/misc.c sanitize_control_message(const char *src, struct gc_arena *gc) · line 2076
Quoted 1 line
src/openvpn/misc.c +1
-0+else if (!check_debug_level (D_SHOW_KEYS ) && (c =='a' && !strncmp (src,"auth-token " ,11 )))
Overly long line. (And not so clear code, but this is in line with the surrounding code, and you already sent an explanation.)
Quoted 33 lines
src/openvpn/push.c +8
-1@@ -309,7 +309,7 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, struct push_list *push_list) {const char *optstr =NULL ; -const struct tls_multi *tls_multi = c->c2.tls_multi; +struct tls_multi *tls_multi = c->c2.tls_multi;const char *const peer_info = tls_multi->peer_info;struct options *o = &c->options;@@ -371,6 +371,13 @@ prepare_push_reply (struct context *c, struct gc_arena *gc,push_option_fmt (gc, push_list,M_USAGE ,"cipher %s" , o->ciphername); } } + +/* If server uses --auth-gen-token and we have an auth token to send to client */ +if (false == tls_multi->auth_token_sent &&NULL != tls_multi->auth_token) + { +push_option_fmt (gc, push_list,M_USAGE ,"auth-token %s" , tls_multi->auth_token); + tls_multi->auth_token_sent = true; + }return true; }src/openvpn/ssl_common.h +0
-0
src/openvpn/ssl_common.h struct tls_multi · line 533
Quoted 8 lines
src/openvpn/ssl_common.h +2
-0@@ -526,6 +526,8 @@ struct tls_multiuint32_t peer_id;bool use_peer_id; +bool auth_token_sent;/**< If server uses --auth-gen-token and +* token has been sent to client */ char *auth_token;/** If server sends a generated auth-token, * this is the token to use for future * user/pass authentications in this session.
ACK, if you wrap the long lines and update the commit message.
-Steffan
Re: [Openvpn-devel] [PATCH 4/5] auth-gen-token: Push generated auth-tokens to the client
Quoted 61 lines · Steffan Karger
src/openvpn/misc.c sanitize_control_message(const char *src, struct gc_arena *gc)
Quoted 15 lines · David Sommerseth
If --auth-gen-token has been enabled and a token has been generated, ensure this token is pushed to the client using the 'auth-token' option.
Signed-off-by David Sommerseth <[email protected]...>--- src/openvpn/misc.c | 5 +++++ src/openvpn/push.c | 9 ++++++++- src/openvpn/ssl_common.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-)src/openvpn/misc.c +0
-0@@ -2073,6 +2073,11 @@ sanitize_control_message(const char *src, struct gc_arena *gc)Wait, what? We have over 2000 lines of '
misc.c'...?src/openvpn/misc.c sanitize_control_message(const char *src, struct gc_arena *gc) · line 2076
Quoted 1 line
src/openvpn/misc.c +1
-0+else if (!check_debug_level (D_SHOW_KEYS ) && (c =='a' && !strncmp (src,"auth-token " ,11 )))Overly long line. (And not so clear code, but this is in line with the surrounding code, and you already sent an explanation.)
Quoted 35 lines
src/openvpn/push.c +8
-1@@ -309,7 +309,7 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, struct push_list *push_list) {const char *optstr =NULL ; -const struct tls_multi *tls_multi = c->c2.tls_multi; +struct tls_multi *tls_multi = c->c2.tls_multi;const char *const peer_info = tls_multi->peer_info;struct options *o = &c->options;@@ -371,6 +371,13 @@ prepare_push_reply (struct context *c, struct gc_arena *gc,push_option_fmt (gc, push_list,M_USAGE ,"cipher %s" , o->ciphername); } } + +/* If server uses --auth-gen-token and we have an auth token to send to client */ +if (false == tls_multi->auth_token_sent &&NULL != tls_multi->auth_token) + { +push_option_fmt (gc, push_list,M_USAGE ,"auth-token %s" , tls_multi->auth_token); + tls_multi->auth_token_sent = true; + }return true; }src/openvpn/ssl_common.h +0
-0@@ -526,6 +526,8 @@ struct tls_multiuint32_t peer_id;bool use_peer_id;
Quoted 9 lines
src/openvpn/ssl_common.h struct tls_multi · line 533
Quoted 6 lines
src/openvpn/ssl_common.h +2
-0+bool auth_token_sent;/**< If server uses --auth-gen-token and +* token has been sent to client */ char *auth_token;/** If server sends a generated auth-token, * this is the token to use for future * user/pass authentications in this session. ACK, if you wrap the long lines and update the commit message.
Thanks a lot! As there were some more slight changes, I decided to send a v2 patch, just for avoid any further confusion.
Signature · 3 lines
kind regards, David Sommerseth
PATCH v2 4/5 auth-gen-token: Push generated auth-tokens to the client
In reply to David SommersethIf --auth-gen-token has been enabled and a token has been generated, ensure this token is pushed to the client using the 'auth-token' option.
This patch will also remove the logging of auth-token values being pushed, unless --verb level is 7 or higher.
v2 - Don't exceed 80 chars line length
- Clarify the magic in sanitize_control_message()
- Relocate auth_token_sent struct member slightly
--- src/openvpn/misc.c | 9 +++++++++ src/openvpn/push.c | 12 +++++++++++- src/openvpn/ssl_common.h | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-)
src/openvpn/misc.c +9 -0
@@ -2073,6 +2073,15 @@ sanitize_control_message(const char *src, struct gc_arena *gc) skip =4 ; redact = true; } +else if (!check_debug_level (D_SHOW_KEYS ) + && (c =='a' && !strncmp (src,"auth-token " ,11 ))) + { +/* Unless --verb is 7 or higher (D_SHOW_KEYS), hide +* the auth-token value coming in the src string +*/ + skip =10 ; + redact = true; + }if (c ==',' )/* end of redacted item? */ {
src/openvpn/push.c +11 -1
@@ -309,7 +309,7 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, struct push_list *push_list) {const char *optstr =NULL ; -const struct tls_multi *tls_multi = c->c2.tls_multi; +struct tls_multi *tls_multi = c->c2.tls_multi;const char *const peer_info = tls_multi->peer_info;struct options *o = &c->options;
@@ -371,6 +371,16 @@ prepare_push_reply (struct context *c, struct gc_arena *gc,push_option_fmt (gc, push_list,M_USAGE ,"cipher %s" , o->ciphername); } } + +/* If server uses --auth-gen-token and we have an auth token +* to send to the client +*/ +if (false == tls_multi->auth_token_sent &&NULL != tls_multi->auth_token) + { +push_option_fmt (gc, push_list,M_USAGE , +"auth-token %s" , tls_multi->auth_token); + tls_multi->auth_token_sent = true; + }return true; }
src/openvpn/ssl_common.h +2 -0
@@ -533,6 +533,8 @@ struct tls_multi* user/pass authentications in this session. */ time_t auth_token_tstamp;/**< timestamp of the generated token */ +bool auth_token_sent;/**< If server uses --auth-gen-token and +* token has been sent to client */ /* * Our session objects. */
Signature · 1 line
1.8.3.1
PATCH 5/5 auth-gen-token: Authenticate generated auth-tokens when client re-authenticates
In reply to David SommersethOn a server with --auth-gen-token enabled, the server will have created a random token and pushed it to the client. When the client needs to renegotiate the connection or otherwise reconnect, it will at this point use the auth-token as password.
Here we check if we have a token generated and that it has been pushed to the client, if so, then we check if the token matches the locally stored token. If everything matches, we're done and the connection is still authenticated.
If the auth-token authentication fails, we delete our local copy of the token and changes the connection to not being authenticated. From this moment of, the client needs to do a full reconnect providing the users password again.
This token authentication also considers the token lifetime, if that have been set via --auth-gen-token. If the token have expired, the client is rejected and needs to do a full reconnect with a new authentication using the users password.
--- src/openvpn/ssl_verify.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
src/openvpn/ssl_verify.c +50 -0
@@ -1139,6 +1139,55 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,string_mod_remap_name (up->username,COMMON_NAME_CHAR_CLASS );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, base this authentication round +* based on this token instead. +*/ +if (session->opt->auth_generate_token && multi->auth_token_sent &&NULL != multi->auth_token) + { +/* Ensure that the username have not changed */ +if (!tls_lock_username (multi, up->username)) + { + ks->authenticated = false; + goto done; + } + +/* If auth-token lifetime have been enabled, ensure the token is still valid */ +if (session->opt->auth_token_lifetime >0 + && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now ) + { +msg (D_HANDSHAKE ,"Auth-token for client expired\n" ); + ks->authenticated = false; + goto done; + } + +if (memcmp_constant_time (multi->auth_token, up->password, +strlen (multi->auth_token)) !=0 ) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE ); +free (multi->auth_token); + multi->auth_token =NULL ; + multi->auth_token_sent = false; + ks->authenticated = false; +tls_deauthenticate (multi); + +msg (D_TLS_ERRORS ,"TLS Auth Error: Auth token verification failed for username '%s' %s" , + up->username, + (session->opt->ssl_flags &SSLF_USERNAME_AS_COMMON_NAME ) ?"[CN SET]" :"" ); + } +else + { + ks->authenticated = true; + +if ((session->opt->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, + (session->opt->ssl_flags &SSLF_USERNAME_AS_COMMON_NAME ) ?"[CN SET]" :"" ); + } + goto done; + } +/* call plugin(s) and/or script */ #ifdef MANAGEMENT_DEF_AUTH if (man_def_auth ==KMDA_DEF )
@@ -1226,6 +1275,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,msg (D_TLS_ERRORS ,"TLS Auth Error: Auth Username/Password verification failed for peer" ); } + done:gc_free (&gc); }
Signature · 1 line
1.8.3.1
Re: [Openvpn-devel] [PATCH 5/5] auth-gen-token: Authenticate generated auth-tokens when client re-authenticates
Hi,
This feature looks very useful, and the code seems to work well. Aside from some nitpicking, I do have some questions on the bigger picture:
Quoted 4 lines · David Sommerseth
On a server with --auth-gen-token enabled, the server will have created a random token and pushed it to the client. When the client needs to renegotiate the connection or otherwise reconnect, it will at this point use the auth-token as password.
How does/should auth-token behave across the various restarts? Should auth-token for example be cleared on a sigusr1?
Quoted 9 lines
Here we check if we have a token generated and that it has been pushed to the client, if so, then we check if the token matches the locally stored token. If everything matches, we're done and the connection is still authenticated.
If the auth-token authentication fails, we delete our local copy of the token and changes the connection to not being authenticated. From this moment of, the client needs to do a full reconnect providing the users password again.
How does the client know this? This patch does not send an AUTH_FAILED (or something similar) to the client. Testing seems to indicate that the server keeps refusing the token, and the client keeps resending it.
Quoted 4 lines
This token authentication also considers the token lifetime, if that have been set via --auth-gen-token. If the token have expired, the client is rejected and needs to do a full reconnect with a new authentication using the users password.
Similar to the above, I don't see a way for the client to understand that the token has expired. That results in the client sending its token indefinitely, like above.
Some more nagging below ;)
Quoted 10 lines
Signed-off-by David Sommerseth <[email protected]...>--- src/openvpn/ssl_verify.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)src/openvpn/ssl_verify.c +0
-0
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1145
Quoted 7 lines
src/openvpn/ssl_verify.c +4
-0@@ -1139,6 +1139,55 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,string_mod_remap_name (up->username,COMMON_NAME_CHAR_CLASS );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, base this authentication round +* based on this token instead. +*/
base ... based, typo?
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1148
Quoted 3 lines
src/openvpn/ssl_verify.c +3
-0+if (session->opt->auth_generate_token && multi->auth_token_sent &&NULL != multi->auth_token) + { +/* Ensure that the username have not changed */
has not changed
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1155
Quoted 7 lines
src/openvpn/ssl_verify.c +7
-0+if (!tls_lock_username (multi, up->username)) + { + ks->authenticated = false; + goto done; + } + +/* If auth-token lifetime have been enabled, ensure the token is still valid */
has been enabled
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1162
Quoted 7 lines
src/openvpn/ssl_verify.c +7
-0+if (session->opt->auth_token_lifetime >0 + && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now ) + { +msg (D_HANDSHAKE ,"Auth-token for client expired\n" ); + ks->authenticated = false; + goto done; + }
As explained above, I think the client should somehow be notified of this expiration, such that it can take action.
Quoted 4 lines
src/openvpn/ssl_verify.c +4
-0+if (memcmp_constant_time (multi->auth_token, up->password, +strlen (multi->auth_token)) !=0 ) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE );
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1177
Quoted 10 lines
src/openvpn/ssl_verify.c +10
-0+free (multi->auth_token); + multi->auth_token =NULL ; + multi->auth_token_sent = false; + ks->authenticated = false; +tls_deauthenticate (multi); + +msg (D_TLS_ERRORS ,"TLS Auth Error: Auth token verification failed for username '%s' %s" , + up->username, + (session->opt->ssl_flags &SSLF_USERNAME_AS_COMMON_NAME ) ?"[CN SET]" :"" ); + }
As above. What should the client do?
-Steffan
Re: [Openvpn-devel] [PATCH 5/5] auth-gen-token: Authenticate generated auth-tokens when client re-authenticates
Quoted 4 lines · Steffan Karger
Hi,
This feature looks very useful, and the code seems to work well. Aside from some nitpicking, I do have some questions on the bigger picture:
Thanks a lot!
Quoted 8 lines · David Sommerseth
Quoted 4 lines
On a server with --auth-gen-token enabled, the server will have created a random token and pushed it to the client. When the client needs to renegotiate the connection or otherwise reconnect, it will at this point use the auth-token as password.
How does/should auth-token behave across the various restarts? Should auth-token for example be cleared on a sigusr1?
This isn't really well defined, from the initial design. This patch is all based upon the --auth-token feature already present in OpenVPN 2.3, and what is possible to do via the plug-in/script mechanisms available today - which works even on v2.3 servers today.
So this feature I introduce here will currently only provide a similar behaviour as if this the external authentication module had implemented --auth-token support. Plug-ins and --auth-user-pass-verify can only return "success" and "fail", which is what this patch in essence does.
With that said, I am not too happy about this ambiguity. But fixing that should be done separately. And we need to ensure we don't break existing v2.3 clients, and I believe we need to update the client code a bit too to achieve these goals.
Quoted 5 lines
Quoted 5 lines
Here we check if we have a token generated and that it has been pushed to the client, if so, then we check if the token matches the locally stored token. If everything matches, we're done and the connection is still authenticated.
Quoted 8 lines
Quoted 4 lines
If the auth-token authentication fails, we delete our local copy of the token and changes the connection to not being authenticated. From this moment of, the client needs to do a full reconnect providing the users password again.
How does the client know this? This patch does not send an
AUTH_FAILED(or something similar) to the client. Testing seems to indicate that the server keeps refusing the token, and the client keeps resending it.
Sending AUTH_FAILED explicit would definitely be a good idea. But it is needed to verify that the OpenVPN is in a state where it can push and that the client can accept the push.
But regardless of this, it this will not change the behaviour much at all. AFAICT, the client code today cannot separate authentication failures based on passwords or tokens or get a reason why the authentication failed. (Unless there are something hidden inside IV_* stuff or Peer-ID).
So what happens? The server goes back to normal username/password authentication, which fails as the token isn't valid as a password to the authentication module. The authentication module rejects and the server sends an AUTH_FAILED, and the client disconnects. At least that's what happens in my testing environment.
If it is possible to send an AUTH_FAILED directly without going via the authentication module, we can do that. But going further than that will most likely require some updates to the client code as well - which I try to avoid in this round.
Quoted 8 lines
Quoted 4 lines
This token authentication also considers the token lifetime, if that have been set via --auth-gen-token. If the token have expired, the client is rejected and needs to do a full reconnect with a new authentication using the users password.
Similar to the above, I don't see a way for the client to understand that the token has expired. That results in the client sending its token indefinitely, like above.
Which would be optimal but equally hard as above, as we're currently lacking a possibility to separate authentication failures.
Quoted 15 lines
Some more nagging below ;)
Quoted 13 lines
Signed-off-by David Sommerseth <[email protected]...>--- src/openvpn/ssl_verify.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)src/openvpn/ssl_verify.c +0
-0@@ -1139,6 +1139,55 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,string_mod_remap_name (up->username,COMMON_NAME_CHAR_CLASS );string_mod (up->password,CC_PRINT ,CC_CRLF ,'_' );
Quoted 6 lines
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1145
Quoted 4 lines
src/openvpn/ssl_verify.c +4
-0+/* If server is configured with --auth-gen-token and we have an +* authentication token for this client, base this authentication round +* based on this token instead. +*/ base ... based, typo?
Yeah ... that needs to be improved. I'll fix that comment.
Quoted 5 lines
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1148
Quoted 3 lines
src/openvpn/ssl_verify.c +3
-0+if (session->opt->auth_generate_token && multi->auth_token_sent &&NULL != multi->auth_token) + { +/* Ensure that the username have not changed */ has not changed
Eeek!
Quoted 9 lines
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1155
Quoted 7 lines
src/openvpn/ssl_verify.c +7
-0+if (!tls_lock_username (multi, up->username)) + { + ks->authenticated = false; + goto done; + } + +/* If auth-token lifetime have been enabled, ensure the token is still valid */ has been enabled
*grmbl*
Quoted 10 lines
src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1162
Quoted 7 lines
src/openvpn/ssl_verify.c +7
-0+if (session->opt->auth_token_lifetime >0 + && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now ) + { +msg (D_HANDSHAKE ,"Auth-token for client expired\n" ); + ks->authenticated = false; + goto done; + }As explained above, I think the client should somehow be notified of this expiration, such that it can take action.
Covered in the discussion above.
Quoted 15 lines
Quoted 4 lines
src/openvpn/ssl_verify.c +4
-0+if (memcmp_constant_time (multi->auth_token, up->password, +strlen (multi->auth_token)) !=0 ) + { +memset (multi->auth_token,0 ,AUTH_TOKEN_SIZE );src/openvpn/ssl_verify.c verify_user_pass(struct user_pass *up, struct tls_multi *multi, · line 1177
Quoted 10 lines
src/openvpn/ssl_verify.c +10
-0+free (multi->auth_token); + multi->auth_token =NULL ; + multi->auth_token_sent = false; + ks->authenticated = false; +tls_deauthenticate (multi); + +msg (D_TLS_ERRORS ,"TLS Auth Error: Auth token verification failed for username '%s' %s" , + up->username, + (session->opt->ssl_flags &SSLF_USERNAME_AS_COMMON_NAME ) ?"[CN SET]" :"" ); + }
Quoted 1 line
As above. What should the client do?
Also covered in discussion above.
Signature · 3 lines
kind regards, David Sommerseth
Re: [Openvpn-devel] [PATCH 5/5] auth-gen-token: Authenticate generated auth-tokens when client re-authenticates
Hi,
Quoted 55 lines · David Sommerseth
Quoted 8 lines · Steffan Karger
Quoted 4 lines · David Sommerseth
On a server with --auth-gen-token enabled, the server will have created a random token and pushed it to the client. When the client needs to renegotiate the connection or otherwise reconnect, it will at this point use the auth-token as password.
How does/should auth-token behave across the various restarts? Should auth-token for example be cleared on a sigusr1?
This isn't really well defined, from the initial design. This patch is all based upon the --auth-token feature already present in OpenVPN 2.3, and what is possible to do via the plug-in/script mechanisms available today - which works even on v2.3 servers today.
So this feature I introduce here will currently only provide a similar behaviour as if this the external authentication module had implemented --auth-token support. Plug-ins and --auth-user-pass-verify can only return "success" and "fail", which is what this patch in essence does.
With that said, I am not too happy about this ambiguity. But fixing that should be done separately. And we need to ensure we don't break existing v2.3 clients, and I believe we need to update the client code a bit too to achieve these goals.
Quoted 5 lines
Quoted 5 lines
Here we check if we have a token generated and that it has been pushed to the client, if so, then we check if the token matches the locally stored token. If everything matches, we're done and the connection is still authenticated.
Quoted 8 lines
Quoted 4 lines
If the auth-token authentication fails, we delete our local copy of the token and changes the connection to not being authenticated. From this moment of, the client needs to do a full reconnect providing the users password again.
How does the client know this? This patch does not send an
AUTH_FAILED(or something similar) to the client. Testing seems to indicate that the server keeps refusing the token, and the client keeps resending it.Sending
AUTH_FAILEDexplicit would definitely be a good idea. But it is needed to verify that the OpenVPN is in a state where it can push and that the client can accept the push.But regardless of this, it this will not change the behaviour much at all. AFAICT, the client code today cannot separate authentication failures based on passwords or tokens or get a reason why the authentication failed. (Unless there are something hidden inside IV_* stuff or Peer-ID).
So what happens? The server goes back to normal username/password authentication, which fails as the token isn't valid as a password to the authentication module. The authentication module rejects and the server sends an
AUTH_FAILED, and the client disconnects. At least that's what happens in my testing environment.
Quoted 4 lines
If it is possible to send an
AUTH_FAILEDdirectly without going via the authentication module, we can do that. But going further than that will most likely require some updates to the client code as well - which I try to avoid in this round.
Ok, so it seems we want the exact same thing, and these are the first step towards it. Let's postpone this for later patches than. I do think we need to look into this before releasing 2.4.0.
If youl fix my nagging point before applying, ACK.
-Steffan