All of lore.kernel.org
 help / color / mirror / Atom feed
* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
@ 2024-10-25 14:45 ` plaisthos (Code Review)
  2024-10-26  9:16 ` cron2 (Code Review)
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: plaisthos (Code Review) @ 2024-10-25 14:45 UTC (permalink / raw)
  To: flichtenheld <frank@; +Cc: openvpn-devel

[-- Attachment #1: Type: text/plain, Size: 5646 bytes --]

Attention is currently required from: flichtenheld.

Hello flichtenheld,

I'd like you to do a code review.
Please visit

    http://gerrit.openvpn.net/c/openvpn/+/787?usp=email

to review the following change.


Change subject: Refuse clients if username or password is > USER_PASS_LEN
......................................................................

Refuse clients if username or password is > USER_PASS_LEN

When OpenVPN is compiled without PKCS11 support USER_PASS_LEN is 128
bytes. If we encounter a username larger than this length we would
only read the 2 bytes length header of the username/password.  We did
then also NOT skip the username or password field meaning that we would
continue reading the rest of the packet at the wrong offset and get
garbage results like not having peerinfo and then rejecting a client
because of no common cipher or missing data v2 support.

This will tell the client that username/password is too regardless
of whether password/username authentication is used.  This way we
do not leak if username/password authentication is active.

To reproduce this issue have the server compiled with a USER_PASS_LEN
set to 128 (e.g. without pkcs11 or manually adjusting the define) and
have the client with a larger USER_PASS_LEN to actually be able to
send the larger password.

Using the openvpn3 test client with overlong username/password also
works.

Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Signed-off-by: Arne Schwabe <arne@...1227...>
---
M src/openvpn/ssl.c
1 file changed, 36 insertions(+), 11 deletions(-)



  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/87/787/1

diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index e2be614..e5f4f2b 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1835,20 +1835,33 @@
     return true;
 }

-static bool
+/**
+ * Read a string that is encoded as a 2 byte header with the length from the
+ * buffer \c buf. Will return the non-negative value if reading was successful.
+ * The returned value will include the trailing 0 byte.
+ *
+ * If the message is over the capacity or could not be read
+ * it will return the negative length that was in the
+ * header and try to skip the string. If the string cannot be skipped, the
+ * buf will stay at the current position or position + 2
+ */
+static int
 read_string(struct buffer *buf, char *str, const unsigned int capacity)
 {
     const int len = buf_read_u16(buf);
     if (len < 1 || len > (int)capacity)
     {
-        return false;
+        buf_advance(buf, len);
+
+        /* will also return 0 for a no string being present */
+        return -len;
     }
     if (!buf_read(buf, str, len))
     {
-        return false;
+        return -len;
     }
     str[len-1] = '\0';
-    return true;
+    return len;
 }

 static char *
@@ -2218,8 +2231,6 @@
 {
     struct key_state *ks = &session->key[KS_PRIMARY];      /* primary key */

-    bool username_status, password_status;
-
     struct gc_arena gc = gc_new();
     char *options;
     struct user_pass *up = NULL;
@@ -2253,7 +2264,7 @@
     }

     /* get options */
-    if (!read_string(buf, options, TLS_OPTIONS_LEN))
+    if (read_string(buf, options, TLS_OPTIONS_LEN) < 0)
     {
         msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string");
         goto error;
@@ -2266,8 +2277,11 @@
      * peer_info data which follows behind
      */
     ALLOC_OBJ_CLEAR_GC(up, struct user_pass, &gc);
-    username_status = read_string(buf, up->username, USER_PASS_LEN);
-    password_status = read_string(buf, up->password, USER_PASS_LEN);
+    int username_len = read_string(buf, up->username, USER_PASS_LEN);
+    int password_len = read_string(buf, up->password, USER_PASS_LEN);
+
+    msg(D_TLS_ERRORS, "TLS INFO: Username (%d) or password (%d)  long",
+        abs(username_len), abs(password_len));

     /* get peer info from control channel */
     free(multi->peer_info);
@@ -2290,10 +2304,21 @@
         multi->remote_ciphername = string_alloc("none", NULL);
     }

-    if (tls_session_user_pass_enabled(session))
+    if (username_len < 0 || password_len < 0)
+    {
+        msg(D_TLS_ERRORS, "TLS Error: Username (%d) or password (%d) too long",
+            abs(username_len), abs(password_len));
+        auth_set_client_reason(multi, "Username or password is too long. "
+                               "Maximum length is 128 bytes");
+
+        /* treat the same as failed username/password and do not error
+         * out (goto error) to sent an AUTH_FAILED back to the client */
+        ks->authenticated = KS_AUTH_FALSE;
+    }
+    else if (tls_session_user_pass_enabled(session))
     {
         /* Perform username/password authentication */
-        if (!username_status || !password_status)
+        if (!username_len || !password_len)
         {
             CLEAR(*up);
             if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))

--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 1
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-MessageType: newchange

[-- Attachment #2: Type: text/html, Size: 9776 bytes --]

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
  2024-10-25 14:45 ` [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN plaisthos (Code Review)
@ 2024-10-26  9:16 ` cron2 (Code Review)
  2024-10-26  9:18 ` cron2 (Code Review)
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: cron2 (Code Review) @ 2024-10-26  9:16 UTC (permalink / raw)
  To: plaisthos <arne-openvpn@; +Cc: flichtenheld <frank@

[-- Attachment #1: Type: text/plain, Size: 2702 bytes --]

Attention is currently required from: flichtenheld, plaisthos.

cron2 has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is > USER_PASS_LEN
......................................................................


Patch Set 1: Code-Review-2

(1 comment)

Patchset:

PS1:
This is not working right for me.

I have a client, built with PKCS11 support, that sends a 230 byte username and a short passwort (11 characters).  On the server side (not built with PKCS11, verified by printing out USER_PASS_LEN at startup), this is using plugin-auth-pam, and it seems to happily pass things onward, in confusing ways

```
2024-10-26 11:10:24 USER_PASS_LEN=128
...
Oct 26 11:06:47 gentoo tun-udp-p2mp-global-authpam[1709]: 194.97.140.21:50280 TLS INFO: Username (128) or password (103)  long
Oct 26 11:06:47 gentoo tun-udp-p2mp-global-authpam[1709]: PLUGIN AUTH-PAM: deferred authentication
Oct 26 11:06:47 gentoo tun-udp-p2mp-global-authpam[1709]: 194.97.140.21:50280 TLS: Username/Password authentication deferred for username 'ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsT'
```

so it's not overrunning the buffer, and not getting confused anymore, but it *is* truncating the username to 128 bytes and using "the rest" for the password (103 = (230-128).  Turning on password logging in plugin-auth-pam confirms:

```
Oct 26 11:06:47 gentoo openvpn[1711]: PLUGIN AUTH-PAM: BACKGROUND: USER/PASS: ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsT/ooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_ThisUserNameIsTooLongReally_230ch
```

(the password the client sends is `totallysecret`, and the client username ends in `_230ch`)



--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 1
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: plaisthos <arne-openvpn@...1227...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-Comment-Date: Sat, 26 Oct 2024 09:16:15 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment

[-- Attachment #2: Type: text/html, Size: 4237 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
  2024-10-25 14:45 ` [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN plaisthos (Code Review)
  2024-10-26  9:16 ` cron2 (Code Review)
@ 2024-10-26  9:18 ` cron2 (Code Review)
  2024-10-27  9:41 ` cron2 (Code Review)
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: cron2 (Code Review) @ 2024-10-26  9:18 UTC (permalink / raw)
  To: plaisthos <arne-openvpn@; +Cc: flichtenheld <frank@

[-- Attachment #1: Type: text/plain, Size: 1544 bytes --]

Attention is currently required from: flichtenheld, plaisthos.

cron2 has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is > USER_PASS_LEN
......................................................................


Patch Set 1:

(1 comment)

File src/openvpn/ssl.c:

http://gerrit.openvpn.net/c/openvpn/+/787/comment/bdf98e73_25fe4401 :
PS1, Line 2284:         abs(username_len), abs(password_len));
I suggest printing the variables without `abs()` so the log is clear *if* there is an overrun - in my case it's always "128", not the expected "-128".  But you can't see that difference or non-difference with the `abs()`...

Also, there's an extra space ;-)



--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 1
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: plaisthos <arne-openvpn@...1227...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-Comment-Date: Sat, 26 Oct 2024 09:18:16 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

[-- Attachment #2: Type: text/html, Size: 2700 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (2 preceding siblings ...)
  2024-10-26  9:18 ` cron2 (Code Review)
@ 2024-10-27  9:41 ` cron2 (Code Review)
  2024-10-27 15:17 ` plaisthos (Code Review)
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: cron2 (Code Review) @ 2024-10-27  9:41 UTC (permalink / raw)
  To: plaisthos <arne-openvpn@; +Cc: flichtenheld <frank@

[-- Attachment #1: Type: text/plain, Size: 2345 bytes --]

Attention is currently required from: flichtenheld, plaisthos.

cron2 has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is > USER_PASS_LEN
......................................................................


Patch Set 1: Code-Review-1

(1 comment)

Patchset:

PS1:
Okay, my client was not compiled the way I thought - so with --enable-pkcs11, sending a long username to an unmodified server yields

```
Oct 27 10:30:59 gentoo tun-udp-p2mp-global-authpam[14201]: 194.97.140.21:36736 TLS Error: Auth Username/Password was not provided by peer
Oct 27 10:30:59 gentoo tun-udp-p2mp-global-authpam[14201]: 194.97.140.21:36736 TLS Error: TLS handshake failed
``

and with the patch it does a proper

```
Oct 27 10:34:48 gentoo tun-udp-p2mp-global-authpam[15712]: 194.97.140.21:60127 TLS INFO: Username (-230) or password (14)  long
...
Oct 27 10:34:48 gentoo tun-udp-p2mp-global-authpam[15712]: 194.97.140.21:60127 TLS Error: Username (230) or password (14) too long
```

and the client receives

```
2024-10-27 10:34:48 AUTH: Received control message: AUTH_FAILED,Username or password is too long. Maximum length is 128 bytes
```

(the "-" 230 is my doing, I removed the abs() call to more clearly see what is being returned).

Upgrading the patch to "-1" ;-) - I think the "TLS INFO:" line clould either be removed (because it's duplicating the TLS Error: message later) or the `abs()` should go, and the double space before `  long`)



-- 
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 1
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: plaisthos <arne-openvpn@...1227...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-Comment-Date: Sun, 27 Oct 2024 09:41:32 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment

[-- Attachment #2: Type: text/html, Size: 4006 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (3 preceding siblings ...)
  2024-10-27  9:41 ` cron2 (Code Review)
@ 2024-10-27 15:17 ` plaisthos (Code Review)
  2024-10-28 10:09 ` cron2 (Code Review)
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: plaisthos (Code Review) @ 2024-10-27 15:17 UTC (permalink / raw)
  Cc: cron2 <gert@

[-- Attachment #1: Type: text/plain, Size: 1770 bytes --]

Attention is currently required from: cron2, flichtenheld.

plaisthos has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is > USER_PASS_LEN
......................................................................


Patch Set 1:

(1 comment)

File src/openvpn/ssl.c:

http://gerrit.openvpn.net/c/openvpn/+/787/comment/801fc40c_ea3a9703 :
PS1, Line 2284:         abs(username_len), abs(password_len));
> I suggest printing the variables without `abs()` so the log is clear *if* there is an overrun - in m […]
I think a negative length is more alarming and confusing that a positive one. If you remove the abs() one of the number will be always negative. Since it errors out now anyway and of them is too long anyway, it is a larger one. I just didn't want to do all the if/else cases and different message for password too long and username too long.



--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 1
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: cron2 <gert@...1296...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-Comment-Date: Sun, 27 Oct 2024 15:17:44 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: cron2 <gert@...1296...>
Gerrit-MessageType: comment

[-- Attachment #2: Type: text/html, Size: 2967 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (4 preceding siblings ...)
  2024-10-27 15:17 ` plaisthos (Code Review)
@ 2024-10-28 10:09 ` cron2 (Code Review)
  2024-10-28 13:12 ` plaisthos (Code Review)
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: cron2 (Code Review) @ 2024-10-28 10:09 UTC (permalink / raw)
  To: plaisthos <arne-openvpn@; +Cc: flichtenheld <frank@

[-- Attachment #1: Type: text/plain, Size: 1922 bytes --]

Attention is currently required from: flichtenheld, plaisthos.

cron2 has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is > USER_PASS_LEN
......................................................................


Patch Set 1:

(1 comment)

File src/openvpn/ssl.c:

http://gerrit.openvpn.net/c/openvpn/+/787/comment/144948ce_63eadfa8 :
PS1, Line 2284:         abs(username_len), abs(password_len));
> I think a negative length is more alarming and confusing that a positive one. […]
You have two messages there - the "TLS INFO:" which is always printed, and only has a negative number if one of the strings is too long.  This is what I'm talking about.

The second message is the "TLS Error:" which is only printed in case of overflow - the abs() is reasonable there.

So I'd suggest to remove the "TLS INFO:" message, because in case of errors it's just duplicate information, and in case of non-errors, it's log noise.  No?



--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 1
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: plaisthos <arne-openvpn@...1227...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-Comment-Date: Mon, 28 Oct 2024 10:09:14 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: plaisthos <arne-openvpn@...1227...>
Comment-In-Reply-To: cron2 <gert@...1296...>
Gerrit-MessageType: comment

[-- Attachment #2: Type: text/html, Size: 3327 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (5 preceding siblings ...)
  2024-10-28 10:09 ` cron2 (Code Review)
@ 2024-10-28 13:12 ` plaisthos (Code Review)
  2024-10-28 13:48 ` [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is longer than USER_PASS_LEN plaisthos (Code Review)
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: plaisthos (Code Review) @ 2024-10-28 13:12 UTC (permalink / raw)
  Cc: cron2 <gert@

[-- Attachment #1: Type: text/plain, Size: 1504 bytes --]

Attention is currently required from: cron2, flichtenheld.

plaisthos has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is > USER_PASS_LEN
......................................................................


Patch Set 1:

(1 comment)

File src/openvpn/ssl.c:

http://gerrit.openvpn.net/c/openvpn/+/787/comment/932858d7_a579b6b4 :
PS1, Line 2284:         abs(username_len), abs(password_len));
> You have two messages there - the "TLS INFO:" which is always printed, and only has a negative numbe […]
Yeah sounds good.



--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 1
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: cron2 <gert@...1296...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-Comment-Date: Mon, 28 Oct 2024 13:12:21 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: plaisthos <arne-openvpn@...1227...>
Comment-In-Reply-To: cron2 <gert@...1296...>
Gerrit-MessageType: comment

[-- Attachment #2: Type: text/html, Size: 2747 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is longer than USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (6 preceding siblings ...)
  2024-10-28 13:12 ` plaisthos (Code Review)
@ 2024-10-28 13:48 ` plaisthos (Code Review)
  2024-10-28 13:54 ` cron2 (Code Review)
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: plaisthos (Code Review) @ 2024-10-28 13:48 UTC (permalink / raw)
  To: cron2 <gert@; +Cc: openvpn-devel

[-- Attachment #1: Type: text/plain, Size: 5933 bytes --]

Attention is currently required from: cron2, flichtenheld.

Hello cron2, flichtenheld,

I'd like you to reexamine a change. Please visit

    http://gerrit.openvpn.net/c/openvpn/+/787?usp=email

to look at the new patch set (#2).

The following approvals got outdated and were removed:
Code-Review-1 by cron2


Change subject: Refuse clients if username or password is longer than USER_PASS_LEN
......................................................................

Refuse clients if username or password is longer than USER_PASS_LEN

When OpenVPN is compiled without PKCS11 support USER_PASS_LEN is 128
bytes. If we encounter a username larger than this length, we would
only read the 2 bytes length header of the username/password.  We did
then also NOT skip the username or password field meaning that we would
continue reading the rest of the packet at the wrong offset and get
garbage results like not having peerinfo and then rejecting a client
because of no common cipher or missing data v2 support.

This will tell the client that username/password is too regardless
of whether password/username authentication is used.  This way we
do not leak if username/password authentication is active.

To reproduce this issue have the server compiled with a USER_PASS_LEN
set to 128 (e.g. without pkcs11 or manually adjusting the define) and
have the client with a larger USER_PASS_LEN to actually be able to
send the larger password. The server must also be set to use only
certificate authentication while the client must use certificates
and auth-user-pass because otherwise the user/pass verification will
reject the empty credentials.

Using the openvpn3 test client with overlong username/password also
works.

Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Signed-off-by: Arne Schwabe <arne@...1227...>
---
M src/openvpn/ssl.c
1 file changed, 33 insertions(+), 11 deletions(-)


  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/87/787/2

diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index e2be614..8040e7b 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1835,20 +1835,33 @@
     return true;
 }

-static bool
+/**
+ * Read a string that is encoded as a 2 byte header with the length from the
+ * buffer \c buf. Will return the non-negative value if reading was successful.
+ * The returned value will include the trailing 0 byte.
+ *
+ * If the message is over the capacity or could not be read
+ * it will return the negative length that was in the
+ * header and try to skip the string. If the string cannot be skipped, the
+ * buf will stay at the current position or position + 2
+ */
+static int
 read_string(struct buffer *buf, char *str, const unsigned int capacity)
 {
     const int len = buf_read_u16(buf);
     if (len < 1 || len > (int)capacity)
     {
-        return false;
+        buf_advance(buf, len);
+
+        /* will also return 0 for a no string being present */
+        return -len;
     }
     if (!buf_read(buf, str, len))
     {
-        return false;
+        return -len;
     }
     str[len-1] = '\0';
-    return true;
+    return len;
 }

 static char *
@@ -2218,8 +2231,6 @@
 {
     struct key_state *ks = &session->key[KS_PRIMARY];      /* primary key */

-    bool username_status, password_status;
-
     struct gc_arena gc = gc_new();
     char *options;
     struct user_pass *up = NULL;
@@ -2253,7 +2264,7 @@
     }

     /* get options */
-    if (!read_string(buf, options, TLS_OPTIONS_LEN))
+    if (read_string(buf, options, TLS_OPTIONS_LEN) < 0)
     {
         msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string");
         goto error;
@@ -2266,8 +2277,8 @@
      * peer_info data which follows behind
      */
     ALLOC_OBJ_CLEAR_GC(up, struct user_pass, &gc);
-    username_status = read_string(buf, up->username, USER_PASS_LEN);
-    password_status = read_string(buf, up->password, USER_PASS_LEN);
+    int username_len = read_string(buf, up->username, USER_PASS_LEN);
+    int password_len = read_string(buf, up->password, USER_PASS_LEN);

     /* get peer info from control channel */
     free(multi->peer_info);
@@ -2290,10 +2301,21 @@
         multi->remote_ciphername = string_alloc("none", NULL);
     }

-    if (tls_session_user_pass_enabled(session))
+    if (username_len < 0 || password_len < 0)
+    {
+        msg(D_TLS_ERRORS, "TLS Error: Username (%d) or password (%d) too long",
+            abs(username_len), abs(password_len));
+        auth_set_client_reason(multi, "Username or password is too long. "
+                               "Maximum length is 128 bytes");
+
+        /* treat the same as failed username/password and do not error
+         * out (goto error) to sent an AUTH_FAILED back to the client */
+        ks->authenticated = KS_AUTH_FALSE;
+    }
+    else if (tls_session_user_pass_enabled(session))
     {
         /* Perform username/password authentication */
-        if (!username_status || !password_status)
+        if (!username_len || !password_len)
         {
             CLEAR(*up);
             if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))

--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 2
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: cron2 <gert@...1296...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-MessageType: newpatchset

[-- Attachment #2: Type: text/html, Size: 9956 bytes --]

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is longer than USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (7 preceding siblings ...)
  2024-10-28 13:48 ` [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is longer than USER_PASS_LEN plaisthos (Code Review)
@ 2024-10-28 13:54 ` cron2 (Code Review)
  2024-10-28 13:55 ` [Openvpn-devel] [PATCH v2] " Gert Doering
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: cron2 (Code Review) @ 2024-10-28 13:54 UTC (permalink / raw)
  To: plaisthos <arne-openvpn@; +Cc: flichtenheld <frank@

[-- Attachment #1: Type: text/plain, Size: 1439 bytes --]

Attention is currently required from: flichtenheld, plaisthos.

cron2 has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is longer than USER_PASS_LEN
......................................................................


Patch Set 2: Code-Review+2

(1 comment)

File src/openvpn/ssl.c:

http://gerrit.openvpn.net/c/openvpn/+/787/comment/2171c946_e254f51c :
PS1, Line 2284:         abs(username_len), abs(password_len));
> Yeah sounds good.
Done



--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 2
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: plaisthos <arne-openvpn@...1227...>
Gerrit-Attention: flichtenheld <frank@...2641...>
Gerrit-Comment-Date: Mon, 28 Oct 2024 13:54:21 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Comment-In-Reply-To: plaisthos <arne-openvpn@...1227...>
Comment-In-Reply-To: cron2 <gert@...1296...>
Gerrit-MessageType: comment

[-- Attachment #2: Type: text/html, Size: 2812 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [PATCH v2] Refuse clients if username or password is longer than USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (8 preceding siblings ...)
  2024-10-28 13:54 ` cron2 (Code Review)
@ 2024-10-28 13:55 ` Gert Doering
  2024-10-28 15:42   ` [Openvpn-devel] [PATCH applied] " Gert Doering
  2024-10-28 15:42 ` [Openvpn-devel] [S] Change in openvpn[master]: " cron2 (Code Review)
  2024-10-28 15:42 ` cron2 (Code Review)
  11 siblings, 1 reply; 13+ messages in thread
From: Gert Doering @ 2024-10-28 13:55 UTC (permalink / raw)
  To: openvpn-devel

From: Arne Schwabe <arne@...1227...>

When OpenVPN is compiled without PKCS11 support USER_PASS_LEN is 128
bytes. If we encounter a username larger than this length, we would
only read the 2 bytes length header of the username/password.  We did
then also NOT skip the username or password field meaning that we would
continue reading the rest of the packet at the wrong offset and get
garbage results like not having peerinfo and then rejecting a client
because of no common cipher or missing data v2 support.

This will tell the client that username/password is too regardless
of whether password/username authentication is used.  This way we
do not leak if username/password authentication is active.

To reproduce this issue have the server compiled with a USER_PASS_LEN
set to 128 (e.g. without pkcs11 or manually adjusting the define) and
have the client with a larger USER_PASS_LEN to actually be able to
send the larger password. The server must also be set to use only
certificate authentication while the client must use certificates
and auth-user-pass because otherwise the user/pass verification will
reject the empty credentials.

Using the openvpn3 test client with overlong username/password also
works.

Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Signed-off-by: Arne Schwabe <arne@...1227...>
Acked-by: Gert Doering <gert@...1296...>
---

This change was reviewed on Gerrit and approved by at least one
developer. I request to merge it to master.

Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/787
This mail reflects revision 2 of this Change.

Acked-by according to Gerrit (reflected above):
Gert Doering <gert@...1296...>

        
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index e2be614..8040e7b 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1835,20 +1835,33 @@
     return true;
 }
 
-static bool
+/**
+ * Read a string that is encoded as a 2 byte header with the length from the
+ * buffer \c buf. Will return the non-negative value if reading was successful.
+ * The returned value will include the trailing 0 byte.
+ *
+ * If the message is over the capacity or could not be read
+ * it will return the negative length that was in the
+ * header and try to skip the string. If the string cannot be skipped, the
+ * buf will stay at the current position or position + 2
+ */
+static int
 read_string(struct buffer *buf, char *str, const unsigned int capacity)
 {
     const int len = buf_read_u16(buf);
     if (len < 1 || len > (int)capacity)
     {
-        return false;
+        buf_advance(buf, len);
+
+        /* will also return 0 for a no string being present */
+        return -len;
     }
     if (!buf_read(buf, str, len))
     {
-        return false;
+        return -len;
     }
     str[len-1] = '\0';
-    return true;
+    return len;
 }
 
 static char *
@@ -2218,8 +2231,6 @@
 {
     struct key_state *ks = &session->key[KS_PRIMARY];      /* primary key */
 
-    bool username_status, password_status;
-
     struct gc_arena gc = gc_new();
     char *options;
     struct user_pass *up = NULL;
@@ -2253,7 +2264,7 @@
     }
 
     /* get options */
-    if (!read_string(buf, options, TLS_OPTIONS_LEN))
+    if (read_string(buf, options, TLS_OPTIONS_LEN) < 0)
     {
         msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string");
         goto error;
@@ -2266,8 +2277,8 @@
      * peer_info data which follows behind
      */
     ALLOC_OBJ_CLEAR_GC(up, struct user_pass, &gc);
-    username_status = read_string(buf, up->username, USER_PASS_LEN);
-    password_status = read_string(buf, up->password, USER_PASS_LEN);
+    int username_len = read_string(buf, up->username, USER_PASS_LEN);
+    int password_len = read_string(buf, up->password, USER_PASS_LEN);
 
     /* get peer info from control channel */
     free(multi->peer_info);
@@ -2290,10 +2301,21 @@
         multi->remote_ciphername = string_alloc("none", NULL);
     }
 
-    if (tls_session_user_pass_enabled(session))
+    if (username_len < 0 || password_len < 0)
+    {
+        msg(D_TLS_ERRORS, "TLS Error: Username (%d) or password (%d) too long",
+            abs(username_len), abs(password_len));
+        auth_set_client_reason(multi, "Username or password is too long. "
+                               "Maximum length is 128 bytes");
+
+        /* treat the same as failed username/password and do not error
+         * out (goto error) to sent an AUTH_FAILED back to the client */
+        ks->authenticated = KS_AUTH_FALSE;
+    }
+    else if (tls_session_user_pass_enabled(session))
     {
         /* Perform username/password authentication */
-        if (!username_status || !password_status)
+        if (!username_len || !password_len)
         {
             CLEAR(*up);
             if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [PATCH applied] Re: Refuse clients if username or password is longer than USER_PASS_LEN
  2024-10-28 13:55 ` [Openvpn-devel] [PATCH v2] " Gert Doering
@ 2024-10-28 15:42   ` Gert Doering
  0 siblings, 0 replies; 13+ messages in thread
From: Gert Doering @ 2024-10-28 15:42 UTC (permalink / raw)
  To: Arne Schwabe <arne@; +Cc: openvpn-devel

Tested this on the local t_server installation, sending overlong usernames
from a client with --enable-pkcs11 - without the patch, there's no crashes
or anything (= not a security relevant bug), but the server gets confused
and does not send a proper TLS FAIL back.  With the patch, the server 
will send a proper AUTH FAIL

   2024-10-27 10:34:48 AUTH: Received control message: AUTH_FAILED,Username or password is too long. Maximum length is 128 bytes

We have a bit more work to do (the client is not properly rejecting
overlong usernames either, at least if reading an "--auth-user-pass up.txt"
file) - but at least the server side is behaving more nicely now.

Your patch has been applied to the master and release/2.6 branch (bugfix).

commit a7f80d402fb95df3c58a8fc5d12cdb8f39c37d3e (master)
commit b98ff0e7c60c6592a2e8d2c80dfd5999e5d2e65b (release/2.6)
Author: Arne Schwabe
Date:   Mon Oct 28 14:55:04 2024 +0100

     Refuse clients if username or password is longer than USER_PASS_LEN

     Signed-off-by: Arne Schwabe <arne@...1227...>
     Acked-by: Gert Doering <gert@...1296...>
     Message-Id: <20241028135505.28651-1-gert@...1296...>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg29675.html
     Signed-off-by: Gert Doering <gert@...1296...>


--
kind regards,

Gert Doering



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is longer than USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (9 preceding siblings ...)
  2024-10-28 13:55 ` [Openvpn-devel] [PATCH v2] " Gert Doering
@ 2024-10-28 15:42 ` cron2 (Code Review)
  2024-10-28 15:42 ` cron2 (Code Review)
  11 siblings, 0 replies; 13+ messages in thread
From: cron2 (Code Review) @ 2024-10-28 15:42 UTC (permalink / raw)
  To: plaisthos <arne-openvpn@; +Cc: openvpn-devel

[-- Attachment #1: Type: text/plain, Size: 5972 bytes --]

cron2 has uploaded a new patch set (#3) to the change originally created by plaisthos. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

The following approvals got outdated and were removed:
Code-Review+2 by cron2


Change subject: Refuse clients if username or password is longer than USER_PASS_LEN
......................................................................

Refuse clients if username or password is longer than USER_PASS_LEN

When OpenVPN is compiled without PKCS11 support USER_PASS_LEN is 128
bytes. If we encounter a username larger than this length, we would
only read the 2 bytes length header of the username/password.  We did
then also NOT skip the username or password field meaning that we would
continue reading the rest of the packet at the wrong offset and get
garbage results like not having peerinfo and then rejecting a client
because of no common cipher or missing data v2 support.

This will tell the client that username/password is too regardless
of whether password/username authentication is used.  This way we
do not leak if username/password authentication is active.

To reproduce this issue have the server compiled with a USER_PASS_LEN
set to 128 (e.g. without pkcs11 or manually adjusting the define) and
have the client with a larger USER_PASS_LEN to actually be able to
send the larger password. The server must also be set to use only
certificate authentication while the client must use certificates
and auth-user-pass because otherwise the user/pass verification will
reject the empty credentials.

Using the openvpn3 test client with overlong username/password also
works.

Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Signed-off-by: Arne Schwabe <arne@...1227...>
Acked-by: Gert Doering <gert@...1296...>
Message-Id: <20241028135505.28651-1-gert@...1296...>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg29675.html
Signed-off-by: Gert Doering <gert@...1296...>
---
M src/openvpn/ssl.c
1 file changed, 33 insertions(+), 11 deletions(-)


  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/87/787/3

diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index e2be614..8040e7b 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1835,20 +1835,33 @@
     return true;
 }

-static bool
+/**
+ * Read a string that is encoded as a 2 byte header with the length from the
+ * buffer \c buf. Will return the non-negative value if reading was successful.
+ * The returned value will include the trailing 0 byte.
+ *
+ * If the message is over the capacity or could not be read
+ * it will return the negative length that was in the
+ * header and try to skip the string. If the string cannot be skipped, the
+ * buf will stay at the current position or position + 2
+ */
+static int
 read_string(struct buffer *buf, char *str, const unsigned int capacity)
 {
     const int len = buf_read_u16(buf);
     if (len < 1 || len > (int)capacity)
     {
-        return false;
+        buf_advance(buf, len);
+
+        /* will also return 0 for a no string being present */
+        return -len;
     }
     if (!buf_read(buf, str, len))
     {
-        return false;
+        return -len;
     }
     str[len-1] = '\0';
-    return true;
+    return len;
 }

 static char *
@@ -2218,8 +2231,6 @@
 {
     struct key_state *ks = &session->key[KS_PRIMARY];      /* primary key */

-    bool username_status, password_status;
-
     struct gc_arena gc = gc_new();
     char *options;
     struct user_pass *up = NULL;
@@ -2253,7 +2264,7 @@
     }

     /* get options */
-    if (!read_string(buf, options, TLS_OPTIONS_LEN))
+    if (read_string(buf, options, TLS_OPTIONS_LEN) < 0)
     {
         msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string");
         goto error;
@@ -2266,8 +2277,8 @@
      * peer_info data which follows behind
      */
     ALLOC_OBJ_CLEAR_GC(up, struct user_pass, &gc);
-    username_status = read_string(buf, up->username, USER_PASS_LEN);
-    password_status = read_string(buf, up->password, USER_PASS_LEN);
+    int username_len = read_string(buf, up->username, USER_PASS_LEN);
+    int password_len = read_string(buf, up->password, USER_PASS_LEN);

     /* get peer info from control channel */
     free(multi->peer_info);
@@ -2290,10 +2301,21 @@
         multi->remote_ciphername = string_alloc("none", NULL);
     }

-    if (tls_session_user_pass_enabled(session))
+    if (username_len < 0 || password_len < 0)
+    {
+        msg(D_TLS_ERRORS, "TLS Error: Username (%d) or password (%d) too long",
+            abs(username_len), abs(password_len));
+        auth_set_client_reason(multi, "Username or password is too long. "
+                               "Maximum length is 128 bytes");
+
+        /* treat the same as failed username/password and do not error
+         * out (goto error) to sent an AUTH_FAILED back to the client */
+        ks->authenticated = KS_AUTH_FALSE;
+    }
+    else if (tls_session_user_pass_enabled(session))
     {
         /* Perform username/password authentication */
-        if (!username_status || !password_status)
+        if (!username_len || !password_len)
         {
             CLEAR(*up);
             if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))

--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 3
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-MessageType: newpatchset

[-- Attachment #2: Type: text/html, Size: 9990 bytes --]

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is longer than USER_PASS_LEN
       [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
                   ` (10 preceding siblings ...)
  2024-10-28 15:42 ` [Openvpn-devel] [S] Change in openvpn[master]: " cron2 (Code Review)
@ 2024-10-28 15:42 ` cron2 (Code Review)
  11 siblings, 0 replies; 13+ messages in thread
From: cron2 (Code Review) @ 2024-10-28 15:42 UTC (permalink / raw)
  To: plaisthos <arne-openvpn@; +Cc: flichtenheld <frank@

[-- Attachment #1: Type: text/plain, Size: 5759 bytes --]

cron2 has submitted this change. ( http://gerrit.openvpn.net/c/openvpn/+/787?usp=email )

Change subject: Refuse clients if username or password is longer than USER_PASS_LEN
......................................................................

Refuse clients if username or password is longer than USER_PASS_LEN

When OpenVPN is compiled without PKCS11 support USER_PASS_LEN is 128
bytes. If we encounter a username larger than this length, we would
only read the 2 bytes length header of the username/password.  We did
then also NOT skip the username or password field meaning that we would
continue reading the rest of the packet at the wrong offset and get
garbage results like not having peerinfo and then rejecting a client
because of no common cipher or missing data v2 support.

This will tell the client that username/password is too regardless
of whether password/username authentication is used.  This way we
do not leak if username/password authentication is active.

To reproduce this issue have the server compiled with a USER_PASS_LEN
set to 128 (e.g. without pkcs11 or manually adjusting the define) and
have the client with a larger USER_PASS_LEN to actually be able to
send the larger password. The server must also be set to use only
certificate authentication while the client must use certificates
and auth-user-pass because otherwise the user/pass verification will
reject the empty credentials.

Using the openvpn3 test client with overlong username/password also
works.

Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Signed-off-by: Arne Schwabe <arne@...1227...>
Acked-by: Gert Doering <gert@...1296...>
Message-Id: <20241028135505.28651-1-gert@...1296...>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg29675.html
Signed-off-by: Gert Doering <gert@...1296...>
---
M src/openvpn/ssl.c
1 file changed, 33 insertions(+), 11 deletions(-)




diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index e2be614..8040e7b 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1835,20 +1835,33 @@
     return true;
 }

-static bool
+/**
+ * Read a string that is encoded as a 2 byte header with the length from the
+ * buffer \c buf. Will return the non-negative value if reading was successful.
+ * The returned value will include the trailing 0 byte.
+ *
+ * If the message is over the capacity or could not be read
+ * it will return the negative length that was in the
+ * header and try to skip the string. If the string cannot be skipped, the
+ * buf will stay at the current position or position + 2
+ */
+static int
 read_string(struct buffer *buf, char *str, const unsigned int capacity)
 {
     const int len = buf_read_u16(buf);
     if (len < 1 || len > (int)capacity)
     {
-        return false;
+        buf_advance(buf, len);
+
+        /* will also return 0 for a no string being present */
+        return -len;
     }
     if (!buf_read(buf, str, len))
     {
-        return false;
+        return -len;
     }
     str[len-1] = '\0';
-    return true;
+    return len;
 }

 static char *
@@ -2218,8 +2231,6 @@
 {
     struct key_state *ks = &session->key[KS_PRIMARY];      /* primary key */

-    bool username_status, password_status;
-
     struct gc_arena gc = gc_new();
     char *options;
     struct user_pass *up = NULL;
@@ -2253,7 +2264,7 @@
     }

     /* get options */
-    if (!read_string(buf, options, TLS_OPTIONS_LEN))
+    if (read_string(buf, options, TLS_OPTIONS_LEN) < 0)
     {
         msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string");
         goto error;
@@ -2266,8 +2277,8 @@
      * peer_info data which follows behind
      */
     ALLOC_OBJ_CLEAR_GC(up, struct user_pass, &gc);
-    username_status = read_string(buf, up->username, USER_PASS_LEN);
-    password_status = read_string(buf, up->password, USER_PASS_LEN);
+    int username_len = read_string(buf, up->username, USER_PASS_LEN);
+    int password_len = read_string(buf, up->password, USER_PASS_LEN);

     /* get peer info from control channel */
     free(multi->peer_info);
@@ -2290,10 +2301,21 @@
         multi->remote_ciphername = string_alloc("none", NULL);
     }

-    if (tls_session_user_pass_enabled(session))
+    if (username_len < 0 || password_len < 0)
+    {
+        msg(D_TLS_ERRORS, "TLS Error: Username (%d) or password (%d) too long",
+            abs(username_len), abs(password_len));
+        auth_set_client_reason(multi, "Username or password is too long. "
+                               "Maximum length is 128 bytes");
+
+        /* treat the same as failed username/password and do not error
+         * out (goto error) to sent an AUTH_FAILED back to the client */
+        ks->authenticated = KS_AUTH_FALSE;
+    }
+    else if (tls_session_user_pass_enabled(session))
     {
         /* Perform username/password authentication */
-        if (!username_status || !password_status)
+        if (!username_len || !password_len)
         {
             CLEAR(*up);
             if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))

-- 
To view, visit http://gerrit.openvpn.net/c/openvpn/+/787?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I60f02c919767eb8f1b95253689a8233f5f68621d
Gerrit-Change-Number: 787
Gerrit-PatchSet: 3
Gerrit-Owner: plaisthos <arne-openvpn@...1227...>
Gerrit-Reviewer: cron2 <gert@...1296...>
Gerrit-Reviewer: flichtenheld <frank@...2641...>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-MessageType: merged

[-- Attachment #2: Type: text/html, Size: 9756 bytes --]

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-10-28 15:42 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <gerrit.1729867531000.I60f02c919767eb8f1b95253689a8233f5f68621d@...2715...>
2024-10-25 14:45 ` [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is > USER_PASS_LEN plaisthos (Code Review)
2024-10-26  9:16 ` cron2 (Code Review)
2024-10-26  9:18 ` cron2 (Code Review)
2024-10-27  9:41 ` cron2 (Code Review)
2024-10-27 15:17 ` plaisthos (Code Review)
2024-10-28 10:09 ` cron2 (Code Review)
2024-10-28 13:12 ` plaisthos (Code Review)
2024-10-28 13:48 ` [Openvpn-devel] [S] Change in openvpn[master]: Refuse clients if username or password is longer than USER_PASS_LEN plaisthos (Code Review)
2024-10-28 13:54 ` cron2 (Code Review)
2024-10-28 13:55 ` [Openvpn-devel] [PATCH v2] " Gert Doering
2024-10-28 15:42   ` [Openvpn-devel] [PATCH applied] " Gert Doering
2024-10-28 15:42 ` [Openvpn-devel] [S] Change in openvpn[master]: " cron2 (Code Review)
2024-10-28 15:42 ` cron2 (Code Review)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.