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 -- F8AC 04D5 0B9B 064B 3383 C3DA AFFC 96D1 151D FFDC