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