[gnutls-devel] BUG: Cannot connect with non-blocking OS to OCSP stapling-enabled (CERTIFICATE STATUS) server
testnutzer123 at gmail.com
Mon Jan 6 15:30:26 CET 2014
Affected: Likely all GnuTLS versions supporting OCSP stapling. Tested
with 3.1.18 and 3.2.8.
- Program client using non-blocking sockets. Or if you're lazy, use
aria2, where we discovered this.
Or wget master, which is affected as well, or something like that.
- Try to connect to a TLS server that uses stapling. E.g. https://tn123.org/
- The connection will fail (more often than not), right after the full
CERTIFICATE STATUS packet is received, with:
"An unexpected TLS handshake packet was received."
- It fails in STATE8 of the handshake (kx) not STATE6 (CERTIFICATE STATUS).
_gnutls_recv_server_certificate_status() does not handle incomplete
packets (EGAIN) correctly.
It sets |priv->expect_cstatus = 0;| before actually checking if there
was already a full packet received. If there wasn't (and this is likely
with non-blocking I/O), the method will later exit, to be called again
when additional data is received.
However, in that subsequent call the function will bail without further
processing as |priv->expect_cstatus| was already set in the first call,
leaving the unprocessed CERTIFICATE STATUS packet in the buffers.
After bailing, the STATE in _gnutls_recv_server_certificate_status()
transitions from STATE6 -> STATE7 -> STATE8. In STATE8,
_gnutls_recv_server_kx_message() is called, with the CERTIFICATE STATUS
still in the buffer, and therefore fails as it rightfully didn't expect
that packet, aborting the connection attempt entirely.
A preliminary test indicates the attached patch (against 3_1_x, because
I'm to lazy to build a nettle-2.7 right now) fixes the problem, by
moving |priv->expect_cstatus = 0;| after the |_gnutls_recv_handshake|
call. I'm not a GnuTLS expert, so I have no idea what it might break in
PS: Please CC me if you need something, as I'm not watching the lists.
-------------- next part --------------
>From d6d4a177e9e705c4bbac0eaa689fa80025f52f71 Mon Sep 17 00:00:00 2001
From: Nils Maier <maierman at web.de>
Date: Mon, 6 Jan 2014 15:15:58 +0100
Subject: [PATCH] Fix CERTIFICATE STATUS processing when using non-blocking I/O
_gnutls_recv_server_certificate_status() must wait for the first full
packet before setting priv->expect_cstatus = 0, or else CERTIFCATE
STATUS packets won't be processed in subsequent calls at all, leaving
them in the buffer and therefore causing later connection aborts.
lib/ext/status_request.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/ext/status_request.c b/lib/ext/status_request.c
index ac512c2..267ba5d 100644
@@ -574,28 +574,28 @@ _gnutls_recv_server_certificate_status (gnutls_session_t session)
_gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_STATUS_REQUEST,
if (ret < 0)
priv = epriv.ptr;
- priv->expect_cstatus = 0;
ret = _gnutls_recv_handshake (session,
if (ret < 0)
+ priv->expect_cstatus = 0;
data = buf.data;
data_size = buf.length;
/* minimum message is type (1) + response (3) + data */
if (data_size == 0)
else if (data_size < 4)
return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
if (data != 0x01)
More information about the Gnutls-devel