summaryrefslogtreecommitdiff
path: root/debian/patches/CVE-2020-15078-1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/CVE-2020-15078-1.patch')
-rw-r--r--debian/patches/CVE-2020-15078-1.patch390
1 files changed, 390 insertions, 0 deletions
diff --git a/debian/patches/CVE-2020-15078-1.patch b/debian/patches/CVE-2020-15078-1.patch
new file mode 100644
index 0000000..9acfc27
--- /dev/null
+++ b/debian/patches/CVE-2020-15078-1.patch
@@ -0,0 +1,390 @@
+From 3aca477a1b58714754fea3a26d0892fffc51db6b Mon Sep 17 00:00:00 2001
+From: Arne Schwabe <arne@rfc2549.org>
+Date: Sat, 27 Mar 2021 18:47:24 +0100
+Subject: [PATCH] Move auth_token_state from multi to key_state
+
+The auth-token check is tied to the username/password that is coming
+via a specific SSL session, so keep the state also in the key_state
+structure.
+
+This also ensures the auth_token_state is always set to 0 on a new
+session since we clear the key_state object at the start of a new
+SSL session.
+
+This is a prerequisite patch to fix 2020-15078 in the following two
+commits.
+
+2nd patch, squashed into the first one:
+
+This also applies the changes to the auth_token_test.c. The change of
+tls_session to a pointer is necessary since before that we had tls_session
+not tied to the multi and had two tls_session used in the test. One
+implicitly in tls_multi and one explicit one. Merge these to one.
+
+CVE: 2020-15078
+Signed-off-by: Arne Schwabe <arne@rfc2549.org>
+Acked-by: Antonio Quartulli <antonio@openvpn.net>
+Message-Id: <d25ec73f-2ab0-31df-8cb6-7778000f4822@openvpn.net>
+URL: non-public, embargoed
+Signed-off-by: Gert Doering <gert@greenie.muc.de>
+---
+ doc/man-sections/example-fingerprint.rst | 0
+ src/openvpn/auth_token.c | 12 +--
+ src/openvpn/ssl_common.h | 4 +-
+ src/openvpn/ssl_verify.c | 8 +-
+ tests/unit_tests/openvpn/test_auth_token.c | 91 +++++++++++-----------
+ 5 files changed, 60 insertions(+), 55 deletions(-)
+ create mode 100644 doc/man-sections/example-fingerprint.rst
+
+diff --git a/doc/man-sections/example-fingerprint.rst b/doc/man-sections/example-fingerprint.rst
+new file mode 100644
+index 000000000..e69de29bb
+diff --git a/src/openvpn/auth_token.c b/src/openvpn/auth_token.c
+index cc70c06c3..0ea6d1832 100644
+--- a/src/openvpn/auth_token.c
++++ b/src/openvpn/auth_token.c
+@@ -57,6 +57,7 @@ add_session_token_env(struct tls_session *session, struct tls_multi *multi,
+ return;
+ }
+
++ int auth_token_state_flags = session->key[KS_PRIMARY].auth_token_state_flags;
+
+ const char *state;
+
+@@ -64,9 +65,9 @@ add_session_token_env(struct tls_session *session, struct tls_multi *multi,
+ {
+ state = "Initial";
+ }
+- else if (multi->auth_token_state_flags & AUTH_TOKEN_HMAC_OK)
++ else if (auth_token_state_flags & AUTH_TOKEN_HMAC_OK)
+ {
+- switch (multi->auth_token_state_flags & (AUTH_TOKEN_VALID_EMPTYUSER|AUTH_TOKEN_EXPIRED))
++ switch (auth_token_state_flags & (AUTH_TOKEN_VALID_EMPTYUSER|AUTH_TOKEN_EXPIRED))
+ {
+ case 0:
+ state = "Authenticated";
+@@ -98,8 +99,8 @@ add_session_token_env(struct tls_session *session, struct tls_multi *multi,
+
+ /* We had a valid session id before */
+ const char *session_id_source;
+- if (multi->auth_token_state_flags & AUTH_TOKEN_HMAC_OK
+- &!(multi->auth_token_state_flags & AUTH_TOKEN_EXPIRED))
++ if (auth_token_state_flags & AUTH_TOKEN_HMAC_OK
++ && !(auth_token_state_flags & AUTH_TOKEN_EXPIRED))
+ {
+ session_id_source = up->password;
+ }
+@@ -236,7 +237,8 @@ generate_auth_token(const struct user_pass *up, struct tls_multi *multi)
+ * a new token with the empty username since we do not want to loose
+ * the information that the username cannot be trusted
+ */
+- if (multi->auth_token_state_flags & AUTH_TOKEN_VALID_EMPTYUSER)
++ struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY];
++ if (ks->auth_token_state_flags & AUTH_TOKEN_VALID_EMPTYUSER)
+ {
+ hmac_ctx_update(ctx, (const uint8_t *) "", 0);
+ }
+diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h
+index 06c32ac1d..d6fd50bd3 100644
+--- a/src/openvpn/ssl_common.h
++++ b/src/openvpn/ssl_common.h
+@@ -166,6 +166,8 @@ enum ks_auth_state {
+ struct key_state
+ {
+ int state;
++ /** The state of the auth-token sent from the client */
++ int auth_token_state_flags;
+
+ /**
+ * Key id for this key_state, inherited from struct tls_session.
+@@ -582,8 +584,6 @@ struct tls_multi
+ * OpenVPN 3 clients sometimes wipes or replaces the username with a
+ * username hint from their config.
+ */
+- int auth_token_state_flags;
+- /**< The state of the auth-token sent from the client last time */
+
+ /* For P_DATA_V2 */
+ uint32_t peer_id;
+diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c
+index 33115eb6c..6fd51505e 100644
+--- a/src/openvpn/ssl_verify.c
++++ b/src/openvpn/ssl_verify.c
+@@ -1269,7 +1269,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
+ */
+ if (session->opt->auth_token_generate && is_auth_token(up->password))
+ {
+- multi->auth_token_state_flags = verify_auth_token(up, multi, session);
++ ks->auth_token_state_flags = verify_auth_token(up, multi, session);
+ if (session->opt->auth_token_call_auth)
+ {
+ /*
+@@ -1278,7 +1278,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
+ * decide what to do with the result
+ */
+ }
+- else if (multi->auth_token_state_flags == AUTH_TOKEN_HMAC_OK)
++ else if (ks->auth_token_state_flags == AUTH_TOKEN_HMAC_OK)
+ {
+ /*
+ * We do not want the EXPIRED or EMPTY USER flags here so check
+@@ -1373,8 +1373,8 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
+ * the initial timestamp and session id can be extracted from it
+ */
+ if (!multi->auth_token
+- && (multi->auth_token_state_flags & AUTH_TOKEN_HMAC_OK)
+- && !(multi->auth_token_state_flags & AUTH_TOKEN_EXPIRED))
++ && (ks->auth_token_state_flags & AUTH_TOKEN_HMAC_OK)
++ && !(ks->auth_token_state_flags & AUTH_TOKEN_EXPIRED))
+ {
+ multi->auth_token = strdup(up->password);
+ }
+diff --git a/tests/unit_tests/openvpn/test_auth_token.c b/tests/unit_tests/openvpn/test_auth_token.c
+index dbde86318..69fc1f8c9 100644
+--- a/tests/unit_tests/openvpn/test_auth_token.c
++++ b/tests/unit_tests/openvpn/test_auth_token.c
+@@ -45,7 +45,7 @@ struct test_context {
+ struct tls_multi multi;
+ struct key_type kt;
+ struct user_pass up;
+- struct tls_session session;
++ struct tls_session *session;
+ };
+
+ /* Dummy functions that do nothing to mock the functionality */
+@@ -100,10 +100,11 @@ setup(void **state)
+ }
+ ctx->multi.opt.auth_token_generate = true;
+ ctx->multi.opt.auth_token_lifetime = 3000;
++ ctx->session = &ctx->multi.session[TM_ACTIVE];
+
+- ctx->session.opt = calloc(1, sizeof(struct tls_options));
+- ctx->session.opt->renegotiate_seconds = 120;
+- ctx->session.opt->auth_token_lifetime = 3000;
++ ctx->session->opt = calloc(1, sizeof(struct tls_options));
++ ctx->session->opt->renegotiate_seconds = 120;
++ ctx->session->opt->auth_token_lifetime = 3000;
+
+ strcpy(ctx->up.username, "test user name");
+ strcpy(ctx->up.password, "ignored");
+@@ -122,7 +123,7 @@ teardown(void **state)
+ free_key_ctx(&ctx->multi.opt.auth_token_key);
+ wipe_auth_token(&ctx->multi);
+
+- free(ctx->session.opt);
++ free(ctx->session->opt);
+ free(ctx);
+
+ return 0;
+@@ -135,7 +136,7 @@ auth_token_basic_test(void **state)
+
+ generate_auth_token(&ctx->up, &ctx->multi);
+ strcpy(ctx->up.password, ctx->multi.auth_token);
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+ }
+
+@@ -146,7 +147,7 @@ auth_token_fail_invalid_key(void **state)
+
+ generate_auth_token(&ctx->up, &ctx->multi);
+ strcpy(ctx->up.password, ctx->multi.auth_token);
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+
+ /* Change auth-token key */
+@@ -155,13 +156,13 @@ auth_token_fail_invalid_key(void **state)
+ free_key_ctx(&ctx->multi.opt.auth_token_key);
+ init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
+
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session), 0);
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0);
+
+ /* Load original test key again */
+ memset(&key, 0, sizeof(key));
+ free_key_ctx(&ctx->multi.opt.auth_token_key);
+ init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+
+ }
+@@ -176,32 +177,32 @@ auth_token_test_timeout(void **state)
+ strcpy(ctx->up.password, ctx->multi.auth_token);
+
+ /* No time has passed */
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+
+ /* Token before validity, should be rejected */
+ now = 100000 - 100;
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED);
+
+ /* Token still in validity, should be accepted */
+- now = 100000 + 2*ctx->session.opt->renegotiate_seconds - 20;
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ now = 100000 + 2*ctx->session->opt->renegotiate_seconds - 20;
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+
+ /* Token past validity, should be rejected */
+- now = 100000 + 2*ctx->session.opt->renegotiate_seconds + 20;
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ now = 100000 + 2*ctx->session->opt->renegotiate_seconds + 20;
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED);
+
+ /* Check if the mode for a client that never updates its token works */
+ ctx->multi.auth_token_initial = strdup(ctx->up.password);
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+
+ /* But not when we reached our timeout */
+- now = 100000 + ctx->session.opt->auth_token_lifetime + 1;
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ now = 100000 + ctx->session->opt->auth_token_lifetime + 1;
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED);
+
+ free(ctx->multi.auth_token_initial);
+@@ -209,22 +210,22 @@ auth_token_test_timeout(void **state)
+
+ /* regenerate the token util it hits the expiry */
+ now = 100000;
+- while (now < 100000 + ctx->session.opt->auth_token_lifetime + 1)
++ while (now < 100000 + ctx->session->opt->auth_token_lifetime + 1)
+ {
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+ generate_auth_token(&ctx->up, &ctx->multi);
+ strcpy(ctx->up.password, ctx->multi.auth_token);
+- now += ctx->session.opt->renegotiate_seconds;
++ now += ctx->session->opt->renegotiate_seconds;
+ }
+
+
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED);
+ ctx->multi.opt.auth_token_lifetime = 0;
+
+ /* Non expiring token should be fine */
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+ }
+
+@@ -253,7 +254,7 @@ auth_token_test_known_keys(void **state)
+ assert_string_equal(now0key0, ctx->multi.auth_token);
+
+ strcpy(ctx->up.password, ctx->multi.auth_token);
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+ }
+
+@@ -277,25 +278,25 @@ auth_token_test_empty_user(void **state)
+
+ generate_auth_token(&ctx->up, &ctx->multi);
+ strcpy(ctx->up.password, ctx->multi.auth_token);
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK);
+
+ now = 100000;
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED);
+ strcpy(ctx->up.username, "test user name");
+
+ now = 0;
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_VALID_EMPTYUSER);
+
+ strcpy(ctx->up.username, "test user name");
+ now = 100000;
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED|AUTH_TOKEN_VALID_EMPTYUSER);
+
+ zerohmac(ctx->up.password);
+- assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
++ assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
+ 0);
+ }
+
+@@ -304,30 +305,32 @@ auth_token_test_env(void **state)
+ {
+ struct test_context *ctx = (struct test_context *) *state;
+
+- ctx->multi.auth_token_state_flags = 0;
++ struct key_state *ks = &ctx->multi.session[TM_ACTIVE].key[KS_PRIMARY];
++
++ ks->auth_token_state_flags = 0;
+ ctx->multi.auth_token = NULL;
+- add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
++ add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
+ assert_string_equal(lastsesion_statevalue, "Initial");
+
+- ctx->multi.auth_token_state_flags = 0;
++ ks->auth_token_state_flags = 0;
+ strcpy(ctx->up.password, now0key0);
+- add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
++ add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
+ assert_string_equal(lastsesion_statevalue, "Invalid");
+
+- ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK;
+- add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
++ ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK;
++ add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
+ assert_string_equal(lastsesion_statevalue, "Authenticated");
+
+- ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED;
+- add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
++ ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED;
++ add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
+ assert_string_equal(lastsesion_statevalue, "Expired");
+
+- ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_VALID_EMPTYUSER;
+- add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
++ ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_VALID_EMPTYUSER;
++ add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
+ assert_string_equal(lastsesion_statevalue, "AuthenticatedEmptyUser");
+
+- ctx->multi.auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED|AUTH_TOKEN_VALID_EMPTYUSER;
+- add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
++ ks->auth_token_state_flags = AUTH_TOKEN_HMAC_OK|AUTH_TOKEN_EXPIRED|AUTH_TOKEN_VALID_EMPTYUSER;
++ add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
+ assert_string_equal(lastsesion_statevalue, "ExpiredEmptyUser");
+ }
+
+@@ -351,7 +354,7 @@ auth_token_test_random_keys(void **state)
+ assert_string_equal(random_token, ctx->multi.auth_token);
+
+ strcpy(ctx->up.password, ctx->multi.auth_token);
+- assert_true(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session));
++ assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
+ }
+
+
+@@ -363,11 +366,11 @@ auth_token_test_key_load(void **state)
+ free_key_ctx(&ctx->multi.opt.auth_token_key);
+ auth_token_init_secret(&ctx->multi.opt.auth_token_key, zeroinline, true);
+ strcpy(ctx->up.password, now0key0);
+- assert_true(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session));
++ assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
+
+ free_key_ctx(&ctx->multi.opt.auth_token_key);
+ auth_token_init_secret(&ctx->multi.opt.auth_token_key, allx01inline, true);
+- assert_false(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session));
++ assert_false(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
+ }
+
+ int