Hi,

I have an issue with a try of my implementation of a secure communication software.

I´m compiling everything on Debian 6.0.7 (openssl 0.9.8o-4squeeze14 and its dev package).

For the application I´m dealing with non-blocking IO for the socket. I can communicate a few bytes between server and client. However when my server answers too much, the conneciton will be closed for both sides when I try to read (SSL_read() returns 0 and the SSL-Error is 5 but the systems errno is 0 all the time). The last SSL_write will always return the amount of bytes I have to send, but ins this setup only 4 Bytes are transmitted to the client. I case I send more than those 4 Bytes the connection will be closed as described.

Here is my SSL relevant code of my server part:
--- SNIP
/* setup our crypto environment */
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_ciphers();
if((ctx->ssl_ctx = SSL_CTX_new(TLSv1_server_method())) == NULL) {
  tproxy_error_die("unable to initialize SSLv3 methods", 1);
}
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_ALL);
SSL_CTX_set_timeout(ctx->ssl_ctx, 300);
if(!SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, ctx->cert_bundle)) {
  tproxy_error_die("unable to read certificate bundle file", 1);
}
if(strlen(ctx->key_file_pw)) {
SSL_CTX_set_default_passwd_cb(ctx->ssl_ctx, private_key_pass_callback);
  SSL_CTX_set_default_passwd_cb_userdata(ctx->ssl_ctx, (void *)ctx);
}
if(!SSL_CTX_use_RSAPrivateKey_file(ctx->ssl_ctx, ctx->key_file, SSL_FILETYPE_PEM)) {
  tproxy_error_die("unable to read key file", 1);
}
SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
SSL_CTX_set_info_callback(ctx->ssl_ctx, apps_ssl_info_callback);
[...]
con->sock = accept(ctx->socket[i], (struct sockaddr *)&in_socket, &s_size);
/* make the accepted socket non-blocking */
if(ioctl(con->sock, FIONBIO, (char *)&enable) < 0) {
  tproxy_error_die("cannot set socket flags", 1);
}
/* create a new SSL context to handle the connection with the peer */
con->ssl = SSL_new(ctx->ssl_ctx);
SSL_set_mode(con->ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE);

/* complete ssl connection */
con->sbio = BIO_new_socket(con->sock, BIO_NOCLOSE);
SSL_set_bio(con->ssl, con->sbio, con->sbio);
/* set chipher */
if (SSL_set_cipher_list(con->ssl,"AES128-SHA") <= 0) {
  tproxy_error_die("unable to set chipher", 1);
}
/* do not require a valid client certificate */
SSL_set_verify(con->ssl, SSL_VERIFY_NONE, NULL);
add_connection(ctx, con);
[...]

   /* later in the connection worker thread */

[...]
while(cur) {
switch(cur->state) {
case CSTATE_SSL_HANDSHAKE:
  /* wait for the client to accept */
  if(1 != SSL_accept(cur->ssl)) {
if(SSL_get_error(cur->ssl, -1) != SSL_ERROR_WANT_READ && SSL_get_error(cur->ssl, -1) != SSL_ERROR_WANT_WRITE) {
      /* an SSL error occured */
      cur->state = CSTATE_TERMINATING;
    }
  } else {
    cur->state = CSTATE_T_SETUP;
  }
  break;
case CSTATE_T_SETUP:
len = SSL_read(cur->ssl, cur->data + cur->data_offset, TPROXY_BUFFER_SIZE - cur->data_offset);
  if(len > 0) {
    cur->data_offset += len;
  } else if(len == 0){
    cur->state = CSTATE_TERMINATING;
  } else {
if(SSL_get_error(cur->ssl, -1) != SSL_ERROR_WANT_READ && SSL_get_error(cur->ssl, -1) != SSL_ERROR_WANT_WRITE) {
      cur->state = CSTATE_TERMINATING;
    } else {
      if(cur->data_offset) {
        [... do something with the data for application handshake...]
    }
  }
  break;
case CSTATE_CONNECTED:
  if(SSL_want(cur->ssl) == SSL_NOTHING) {
    [...] check if something is in the pipe to send [...]
if(proto_data->len != SSL_write(cur->ssl, proto_data, proto_data->len)) {
      [...handle the partial send (never notices)...]
    }
  }
len = SSL_read(cur->ssl, cur->data + cur->data_offset, TPROXY_BUFFER_SIZE - cur->data_offset);
  if(len > 0) {
    cur->data_offset += len;
  } else if(len == 0){
    [...here is the actual error I´m talking about...]
  } else {
if(SSL_get_error(cur->ssl, -1) != SSL_ERROR_WANT_READ && SSL_get_error(cur->ssl, -1) != SSL_ERROR_WANT_WRITE) {
      cur->state = CSTATE_TERMINATING;
    } else {
      if(cur->data_offset) {
        [... do something with the data for application ...]
    }
  }
  break;
[...]
----SNIP

I guess there was nothing special about it. The client is almost equal - except that it do not handle multiple connections in a structure (cur) as it only has one ssl connection a time to the server:

----SNIP
  /* setup ssl stuff */
  SSL_load_error_strings();
  SSL_library_init();
  OpenSSL_add_all_ciphers();
  if(NULL == (ctx->ssl_ctx = SSL_CTX_new(TLSv1_client_method()))) {
    tproxy_error_die("unable to initialize ssl environment", 1);
  }
  SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
  SSL_CTX_set_info_callback(ctx->ssl_ctx, apps_ssl_info_callback);
[...]
if(connect(ctx->proxy_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
    close(ctx->proxy_socket);
    tproxy_error_die("unable to connect", 1);
  }
  if(ioctl(ctx->proxy_socket, FIONBIO, (char *)&enable) < 0) {
    tproxy_error_die("cannot modify socket", 1);
  }
  SSL_CTX_set_timeout(ctx->ssl_ctx, 300);
  ctx->ssl = SSL_new(ctx->ssl_ctx);
  if (SSL_set_cipher_list(ctx->ssl, "AES128-SHA") <= 0) {
    tproxy_error_die("unable to set chipher", 1);
  }
  ctx->bio = BIO_new_socket(ctx->proxy_socket, BIO_NOCLOSE);
  SSL_set_bio(ctx->ssl, ctx->bio, ctx->bio);
  SSL_set_mode(ctx->ssl, SSL_MODE_AUTO_RETRY);
  while(1 != (len = SSL_connect(ctx->ssl))) {
    switch(SSL_get_error(ctx->ssl, len)) {
      case SSL_ERROR_WANT_WRITE:
      case SSL_ERROR_WANT_READ:
        usleep(10000);
        /* everything went fine (->non-blocking connect) */
        break;
      default:
        tproxy_error_die("unable to connect", 1);
    }
  }

  peer = SSL_get_peer_certificate(ctx->ssl);
X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, common_name, sizeof(common_name));
  printf("cn of peer: %s\n", common_name);
[... prepare application handshake ...]
  if(len != SSL_write(ctx->ssl, init_data_out, len)) {
    [... handle it (program was never here)...]
  }
  /* getting the configuration of the server */
  while(buf_offset < sizeof(struct proxy_proto_init_resp)) {
len = SSL_read(ctx->ssl, buffer + buf_offset, BUFFER_SIZE - buf_offset);
    if(len <= 0) {
      switch(SSL_get_error(ctx->ssl, len)) {
        case SSL_ERROR_WANT_WRITE:
        case SSL_ERROR_WANT_READ:
          usleep(10000);
          /* everything went fine (->non-blocking connect) */
          break;
        default:
          tproxy_error_die("did not receive configuration", 1);
      }
    } else {
      buf_offset += len;
    }
  }
[...setup application for user...]
while(1) {
    /***** recv from ssl link *****/
    ERR_print_errors(ctx->bio);
len = SSL_read(ctx->ssl, buffer + buf_offset, sizeof(BUFFER_SIZE) - buf_offset);
    t_err = errno;
    if(len > 0) {
printf("%d bytes recvd %.*s\n", len, len, buffer + buf_offset); // debugging
      buf_offset += len;
    } else if(len == 0) {
      ERR_print_errors(ctx->bio);
      if(SSL_ERROR_SYSCALL == SSL_get_error(ctx->ssl, len)) {
        printf("fatal:%s\n", strerror(t_err));
      }
      ERR_print_errors(ctx->bio);
tproxy_error_die("connection broken 1", SSL_get_error(ctx->ssl, len));
    } else {
if(SSL_get_error(ctx->ssl, -1) != SSL_ERROR_WANT_READ && SSL_get_error(ctx->ssl, -1) != SSL_ERROR_WANT_WRITE) {
        tproxy_error_die("connection broken 2", 1);
      } else {
        [... do something with the date in the application ...]
      }
    }
}
[...]
----SNIP

Sending application data to the server is currently not implementet as the server is not able to send the first application related message (>4 bytes) to the client. However the application handshake proceeds without any problems.

The msg-callback and my debugging writes the following information into the stdout:
CLIENT:
SSL_connect:before/connect initialization
SSL_connect:SSLv3 write client hello A
SSL_connect:error in SSLv3 read server hello A
SSL_connect:SSLv3 read server hello A
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL_connect:error in SSLv3 read server session ticket A
SSL_connect:SSLv3 read server session ticket A
SSL_connect:SSLv3 read finished A
fatal:Success
fatal:connection broken 1
Error: error:00000000:lib(0):func(0):reason(0)

SERVER:
SSL_accept:before/accept initialization
SSL_accept:error in SSLv3 read client hello B
SSL_accept:SSLv3 read client hello B
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write server done A
SSL_accept:SSLv3 flush data
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:error in SSLv3 read client certificate A
SSL_accept:SSLv3 read client key exchange A
SSL_accept:SSLv3 read finished A
SSL_accept:SSLv3 write session ticket A
SSL_accept:SSLv3 write change cipher spec A
SSL_accept:SSLv3 write finished A
SSL_accept:SSLv3 flush data


I´m happy about any hint and any idea! Is there anything I can do for deeper debugging openssl?

Thank you.

Mario
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to