[gnutls-dev] Re: SSL_connect and non-blocking i/o
Jefferson Ogata
Jefferson.Ogata at noaa.gov
Thu Jul 13 16:41:48 CEST 2006
On 2006-07-13 12:15, Simon Josefsson wrote:
> Emile van Bergen <emile-gnutls at e-advies.nl> writes:
>> On Thu, Jul 13, 2006 at 12:53:00AM +0000, Jefferson Ogata wrote:
>>> So I'm debugging an application that uses the gnutls/OpenSSL
>>> compatibility and is using a non-blocking socket for the underlying
>>> transport; it returns from SSL_connect() without completing a handshake.
>>> I tweak gnutls libextra/gnutls_openssl.c as follows and that fixes my
>>> problem:
>>>
>>> - err = gnutls_handshake(ssl->gnutls_state);
>>> + do
>>> + {
>>> + err = gnutls_handshake(ssl->gnutls_state);
>>> + } while (err < 0 && !gnutls_error_is_fatal (err));
>>>
>>> I can't be the only person who has run into this, can I?
>> The idea is that you only repeat the call, but wait first till you
>> estimate it can now do a bit more, eg. because select has indicated data
>> has become available in the socket.
>>
>> Simply adding a loop would seem to create a busy wait for data to
>> appear, and that can't be good.
First of all, my diff was not intended as a final patch, but merely to
document that something is not implemented correctly in SSL_connect().
> I thought that the SSL_connect API in OpenSSL was supposed to block,
> but the man page reads:
>
> If the underlying BIO is blocking, SSL_connect() will only return once
> the handshake has been finished or an error occurred.
>
> If the underlying BIO is non-blocking, SSL_connect() will also return
> when the underlying BIO could not satisfy the needs of SSL_connect() to
> continue the handshake, indicating the problem by the return value -1.
Let's look at a little more context in SSL_connect():
memset (x_priority, 0, sizeof (x_priority));
if (ssl->options & SSL_OP_NO_TLSv1)
{
for (i = 0, j = 0;
i < GNUTLS_MAX_ALGORITHM_NUM && x_priority[i] != 0; i++, j++)
{
if (ssl->ctx->method->protocol_priority[j] == GNUTLS_TLS1)
j++;
else
x_priority[i] = ssl->ctx->method->protocol_priority[j];
}
if (i < GNUTLS_MAX_ALGORITHM_NUM)
x_priority[i] = 0;
gnutls_protocol_set_priority (ssl->gnutls_state,
ssl->ctx->method->protocol_priority);
}
err = gnutls_handshake (ssl->gnutls_state);
ssl->last_error = err;
if (err < 0)
{
last_error = err;
return 0;
}
As you can see, your SSL_connect() returns 0 regardless of the error, so
the caller won't know that SSL_connect() needs to be called again.
In addition, you have this loop to call gnutls_protocol_set_priority()
on every entrance to SSL_connect() regardless of the connection state.
Is it safe/advisable to call gnutls SSL_connect() repeatedly?
Then there's the fact that you ignore the return value from the
verification callback, fail to implement SSL_*_set_verify_depth(), fail
to #define or implement SSL_VERIFY_PEER, SSL_VERIFY_IF_NO_PEER_CERT,
SSL_VERIFY_CLIENT_ONCE, fail to do certificate preverification, fail to
implement SSL_*_load_verify_locations(), but we can get to all that
later (I'll be happy to help). :^)
--
Jefferson Ogata <Jefferson.Ogata at noaa.gov>
NOAA Computer Incident Response Team (N-CIRT) <ncirt at noaa.gov>
"Never try to retrieve anything from a bear."--National Park Service
More information about the Gnutls-dev
mailing list