This has been driving me nuts for the past few weeks... I've written a simple app that demonstrates the problem I'm running into. Basically, a client connects to a server, they do the handshake, and all is well... or should be. Both machines are running linux. Below is the source, and below that is some sample output for the client and server:
source: --------------------------------------------------------------------------- #include <openssl/ssl.h> #include <openssl/err.h> #include <sys/select.h> #include <errno.h> #include <stdio.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/types.h> struct sbio { BIO * bio; BIO * abio; SSL * ssl; int sock; struct sbio * next; }; int max_val(int a, int b) { if(a > b) return a; return b; } SSL_CTX * init_ctx(SSL_METHOD * method) { SSL_CTX * ctx; if(!(ctx = SSL_CTX_new(method))) { fprintf(stderr, "SSL_CTX_new: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL); SSL_CTX_set_verify_depth(ctx, 1); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); if(SSL_CTX_use_certificate_chain_file(ctx, "cert.pem") != 1) { // load certificate file fprintf(stderr, "SSL_CTX_use_certificate_chain_file: %s\n", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); exit(1); } if(SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) != 1) { // load private key fprintf(stderr, "SSL_CTX_use_PrivateKey_file: %s\n", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); exit(1); } if(!SSL_CTX_check_private_key(ctx)) { // check private key fprintf(stderr, "SSL_CTX_check_private_key: %s\n", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); exit(1); } if(!SSL_CTX_load_verify_locations(ctx, "/tmp/ca.pem", NULL)) { // load CA file fprintf(stderr, "SSL_CTX_load_verify_locations: %s\n", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(ctx); exit(1); } return ctx; } int main(int argc, char ** argv) { int client = 0; // client or server int n, counter, nfds; SSL_METHOD method; SSL_CTX * ctx; fd_set afds, rfds; struct sbio mysock; struct sbio * client_head = NULL, * sbiotmp, * sbiotmp1; char buffer[0xff]; mysock.next = NULL; if(!strcmp(argv[1], "client")) { client = 1; } SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); SSL_library_init(); if(client) { memcpy(&method, SSLv3_client_method(), sizeof(SSL_METHOD)); } else { memcpy(&method, SSLv3_server_method(), sizeof(SSL_METHOD)); } ctx = init_ctx(&method); if(!client) { // run server... if(!(mysock.bio = BIO_new_ssl(ctx, 0))) { fprintf(stderr, "BIO_new_ssl: %s", ERR_error_string(ERR_get_error(), NULL)); return 1; } BIO_get_ssl(mysock.bio, &mysock.ssl); snprintf(buffer, 0xff, "%s:%d", argv[2], ntohs(5555)); if(!(mysock.abio = BIO_new_accept(buffer))) { fprintf(stderr, "BIO_new_ssl_accept: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } BIO_set_accept_bios(mysock.abio, mysock.bio); if(BIO_do_accept(mysock.abio) <= 0) { fprintf(stderr, "BIO_do_accept: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } if(BIO_get_fd(mysock.abio, &mysock.sock) == -1) { fprintf(stderr, "BIO_get_fd: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } while(1) { FD_ZERO(&afds); FD_SET(mysock.sock, &afds); nfds = mysock.sock; for(sbiotmp = client_head; sbiotmp; sbiotmp = sbiotmp->next) { FD_SET(sbiotmp->sock, &afds); nfds = max_val(nfds, sbiotmp->sock); } memcpy((char *)&rfds, (char *)&afds, sizeof(fd_set)); if((n = select(nfds + 1, &rfds, NULL, NULL, NULL)) < 0) { fprintf(stderr, "select: %s\n", strerror(errno)); return 1; } if(FD_ISSET(mysock.sock, &rfds)) { printf("Adding a client\n"); if(BIO_do_accept(mysock.abio) <= 0) { fprintf(stderr, "BIO_do_accept: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } sbiotmp = (sbio *)malloc(sizeof(struct sbio)); client = sizeof(struct sockaddr_in); sbiotmp->bio = BIO_pop(mysock.bio); sbiotmp->abio = NULL; sbiotmp->ssl = NULL; if(BIO_do_handshake(sbiotmp->bio) <= 0) { fprintf(stderr, "BIO_do_handshake: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } if(BIO_get_fd(sbiotmp->bio, &sbiotmp->sock) == -1) { fprintf(stderr, "BIO_get_fd: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } sbiotmp->next = client_head; client_head = sbiotmp; } for(sbiotmp = client_head; sbiotmp; sbiotmp = sbiotmp->next) { if(FD_ISSET(sbiotmp->sock, &rfds)) { if(BIO_read(sbiotmp->bio, buffer, 1) <= 0) { printf("Removing a client\n"); if(client_head == sbiotmp) { client_head = sbiotmp->next; } else { for(sbiotmp1 = client_head; sbiotmp1; sbiotmp1 = sbiotmp1->next) { if(sbiotmp1->next == sbiotmp) { sbiotmp1->next = sbiotmp->next; } } } } else { printf("Received character: %c\n", buffer[0]); } } } } } else { // run client... mysock.abio = NULL; snprintf(buffer, 0xff, "%d", ntohs(5555)); if(!(mysock.bio = BIO_new_ssl_connect(ctx))) { fprintf(stderr, "BIO_new_ssl_connect: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } BIO_get_ssl(mysock.bio, &mysock.ssl); SSL_set_mode(mysock.ssl, SSL_MODE_AUTO_RETRY); BIO_set_conn_hostname(mysock.bio, argv[2]); BIO_set_conn_port(mysock.bio, buffer); if(BIO_do_connect(mysock.bio->next_bio) <= 0) { fprintf(stderr, "BIO_do_connect: %s\n", ERR_error_string(ERR_get_error(), NULL)); BIO_free_all(mysock.bio); return 1; } if(SSL_get_verify_result(mysock.ssl) != X509_V_OK) { fprintf(stderr, "SSL_get_verify_result: %ld\n", SSL_get_verify_result(mysock.ssl)); BIO_free_all(mysock.bio); return 1; } if(BIO_get_fd(mysock.bio, &mysock.sock) == -1) { fprintf(stderr, "BIO_get_fd: %s\n", ERR_error_string(ERR_get_error(), NULL)); BIO_free_all(mysock.bio); return 1; } if(BIO_write(mysock.bio, "a", 1) <= 0) { fprintf(stderr, "BIO_write\n"); return 1; } } } Client output: ---------------------------------------------------------------------------- ./a.out client some.ip BIO_write Server output: ---------------------------------------------------------------------------- ./a.out server some.ip Adding a client BIO_do_handshake: error:00000000:lib(0):func(0):reason(0) As you can see... the error is very helpful indeed. Any idea what's happening? I've tried to simplify this as much as possible. -- Life without passion is death in disguise ----------------------------------------- This email was sent using SquirrelMail. "Webmail for nuts!" http://squirrelmail.org/ ______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List openssl-users@openssl.org Automated List Manager majord...@openssl.org