[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