[gnutls-devel] gnutls_record_send after incomplete gnutls_handshake sends data unencrypted

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[gnutls-devel] gnutls_record_send after incomplete gnutls_handshake sends data unencrypted

Andreas Metzler-3
Hello,

find attached bug-report http://bugs.debian.org/849807 as reported by
Bernhard R. Link. The related bug against sssd-ldap is
<http://bugs.debian.org/849756>

cu Andreas

----- Forwarded message from "Bernhard R. Link" <[hidden email]> -----
Package: libgnutls30
Version: 3.5.7-3
Severity: normal
Tags: security

This bug report is not about wrong behavior if libgnutls is called
correctly but rather about dangerous behaviour if the caller is using
libgnutls incorrectly.

If a handshake has not yet completed (the caller ignoring
gnutls_handshake return code or the caller having a bug in the handling
of GNUTLS_E_AGAIN) then telling libgnutls to send data causes it to send
it unencrypted. Unless there are cases where might be useful, I think a
security relevelant library like libgnutls should rather catch this
mistake and avoid sending stuff unencrypted.

Here's an example:

cat <<'EOF' > example.c
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <gnutls/gnutls.h>

static ssize_t sim_write(gnutls_transport_ptr_t session, const void *data, size_t len) {
        bool found = memmem(data, len, "SECRET", 6) != NULL;
        printf("Would have written %d bytes%s.\n", (int)len, found?" containing unencrypted plain-text secret":"");
        fflush(stdout);
        return len;
}
static ssize_t sim_read(gnutls_transport_ptr_t session, void *data, size_t len) {
        /* simulate non-blocking io with no incoming data arrived yet */
        gnutls_transport_set_errno(session, EAGAIN);
        fflush(stdout);
        return -1;
}

int main() {
        gnutls_certificate_credentials_t xcred;
        gnutls_session_t session;
        int r;

        r = gnutls_global_init();
        assert (r == GNUTLS_E_SUCCESS);
        r = gnutls_certificate_allocate_credentials(&xcred);
        assert (r == GNUTLS_E_SUCCESS);
        r = gnutls_init(&session, GNUTLS_CLIENT);
        assert (r == GNUTLS_E_SUCCESS);
        r = gnutls_set_default_priority(session);
        assert (r == GNUTLS_E_SUCCESS);
        r = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
        assert (r == GNUTLS_E_SUCCESS);
        gnutls_session_set_verify_cert(session, "server", 0);

        gnutls_transport_set_ptr(session, session);
        gnutls_transport_set_push_function(session, sim_write);
        gnutls_transport_set_pull_function(session, sim_read);

        r = gnutls_handshake(session);
        assert (r == GNUTLS_E_AGAIN);
        /* ignoring the return code and doing the sending: */
        r = gnutls_record_send(session, "SECRET\n", 7);
        printf("gnutls_record_send returned %d\n", r);

        return 0;
}
EOF
gcc -Wall -O2 -g example.c -lgnutls && ./a.out

It outputs:

Would have written 238 bytes.
Would have written 12 bytes containing unencrypted plain-text secret.
gnutls_record_send returned 7

i.e. the data is send unencrypted (looking at the output one sees a
CLIENT_HELO followed by an APPLICATION_DATA packet with unencrypted
content).

One example where this happens is libldap, which runs into this if
gotten an non-blocking fd (as currently sssd does, see #849756),
causing sssd-ldap to corrently sending passwords unencrypted.

        Bernhard R. Link
--
----- End forwarded message -----

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] gnutls_record_send after incomplete gnutls_handshake sends data unencrypted

Nikos Mavrogiannopoulos
Thank you. That's certainly something to be addressed at least in the
new 3.6.x branch. I've created an issue on the gitlab interface:
https://gitlab.com/gnutls/gnutls/issues/158

I'm wondering however, whether this could have side-effects, i.e.,
whether some existing program relied on that behavior to send TLS
application data records prior to handshake being complete.

regards,
Nikos


On Sat, Dec 31, 2016 at 1:13 PM, Andreas Metzler <[hidden email]> wrote:

> Hello,
>
> find attached bug-report http://bugs.debian.org/849807 as reported by
> Bernhard R. Link. The related bug against sssd-ldap is
> <http://bugs.debian.org/849756>
>
> cu Andreas
>
> ----- Forwarded message from "Bernhard R. Link" <[hidden email]> -----
> Package: libgnutls30
> Version: 3.5.7-3
> Severity: normal
> Tags: security
>
> This bug report is not about wrong behavior if libgnutls is called
> correctly but rather about dangerous behaviour if the caller is using
> libgnutls incorrectly.
>
> If a handshake has not yet completed (the caller ignoring
> gnutls_handshake return code or the caller having a bug in the handling
> of GNUTLS_E_AGAIN) then telling libgnutls to send data causes it to send
> it unencrypted. Unless there are cases where might be useful, I think a
> security relevelant library like libgnutls should rather catch this
> mistake and avoid sending stuff unencrypted.
>
> Here's an example:
>
> cat <<'EOF' > example.c
> #define _GNU_SOURCE
> #include <stdbool.h>
> #include <stdio.h>
> #include <error.h>
> #include <errno.h>
> #include <string.h>
> #include <assert.h>
> #include <gnutls/gnutls.h>
>
> static ssize_t sim_write(gnutls_transport_ptr_t session, const void *data, size_t len) {
>         bool found = memmem(data, len, "SECRET", 6) != NULL;
>         printf("Would have written %d bytes%s.\n", (int)len, found?" containing unencrypted plain-text secret":"");
>         fflush(stdout);
>         return len;
> }
> static ssize_t sim_read(gnutls_transport_ptr_t session, void *data, size_t len) {
>         /* simulate non-blocking io with no incoming data arrived yet */
>         gnutls_transport_set_errno(session, EAGAIN);
>         fflush(stdout);
>         return -1;
> }
>
> int main() {
>         gnutls_certificate_credentials_t xcred;
>         gnutls_session_t session;
>         int r;
>
>         r = gnutls_global_init();
>         assert (r == GNUTLS_E_SUCCESS);
>         r = gnutls_certificate_allocate_credentials(&xcred);
>         assert (r == GNUTLS_E_SUCCESS);
>         r = gnutls_init(&session, GNUTLS_CLIENT);
>         assert (r == GNUTLS_E_SUCCESS);
>         r = gnutls_set_default_priority(session);
>         assert (r == GNUTLS_E_SUCCESS);
>         r = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
>         assert (r == GNUTLS_E_SUCCESS);
>         gnutls_session_set_verify_cert(session, "server", 0);
>
>         gnutls_transport_set_ptr(session, session);
>         gnutls_transport_set_push_function(session, sim_write);
>         gnutls_transport_set_pull_function(session, sim_read);
>
>         r = gnutls_handshake(session);
>         assert (r == GNUTLS_E_AGAIN);
>         /* ignoring the return code and doing the sending: */
>         r = gnutls_record_send(session, "SECRET\n", 7);
>         printf("gnutls_record_send returned %d\n", r);
>
>         return 0;
> }
> EOF
> gcc -Wall -O2 -g example.c -lgnutls && ./a.out
>
> It outputs:
>
> Would have written 238 bytes.
> Would have written 12 bytes containing unencrypted plain-text secret.
> gnutls_record_send returned 7
>
> i.e. the data is send unencrypted (looking at the output one sees a
> CLIENT_HELO followed by an APPLICATION_DATA packet with unencrypted
> content).
>
> One example where this happens is libldap, which runs into this if
> gotten an non-blocking fd (as currently sssd does, see #849756),
> causing sssd-ldap to corrently sending passwords unencrypted.
>
>         Bernhard R. Link
> --
> ----- End forwarded message -----
>
> _______________________________________________
> Gnutls-devel mailing list
> [hidden email]
> http://lists.gnupg.org/mailman/listinfo/gnutls-devel

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [gnutls-devel] gnutls_record_send after incomplete gnutls_handshake sends data unencrypted

Nikos Mavrogiannopoulos
On Mon, Jan 2, 2017 at 10:41 AM, Nikos Mavrogiannopoulos
<[hidden email]> wrote:
> Thank you. That's certainly something to be addressed at least in the
> new 3.6.x branch. I've created an issue on the gitlab interface:
> https://gitlab.com/gnutls/gnutls/issues/158
>
> I'm wondering however, whether this could have side-effects, i.e.,
> whether some existing program relied on that behavior to send TLS
> application data records prior to handshake being complete.

A fix is available at:
https://gitlab.com/gnutls/gnutls/merge_requests/228

regards,
Nikos

_______________________________________________
Gnutls-devel mailing list
[hidden email]
http://lists.gnupg.org/mailman/listinfo/gnutls-devel
Loading...