Error with SSL_do_handshake(), err returns 1 at first call

55 Views Asked by At
void acceptcb(evconnlistener *listener, int fd,
     sockaddr *addr, int addrlen, void *arg) {
    info_log("new conn accepted");
     auto *server_dt = (server_data *)arg;
     SSL *ssl = initializeSSL(server_dt->app_ctx->ssl_ctx, fd);

     if (doHandshake(ssl) < 0) {
         error_log("handshake error, returning");
         return;
     }
    printf("handshake succesfull");

     const unsigned char *alpn = nullptr;
     unsigned int alpn_len = 0;
     SSL_get0_alpn_selected(ssl, &alpn, &alpn_len);
     info_log("alpn: %s\n", alpn);
 }


 SSL *initializeSSL(SSL_CTX *SSL_ctx, int fd) {
     SSL *ssl = SSL_new(SSL_ctx);
     BIO *bio = BIO_new_socket(fd, BIO_NOCLOSE);
     SSL_set_bio(ssl, bio, bio);
//   2 lines above can be changed to SSL_set_fd(ssl, fd) with no effect
     return ssl;
 }

 int doHandshake(SSL *ssl) {
     ERR_clear_error();
     while (true) {
         int ret = SSL_do_handshake(ssl);
         if (ret > 0) {
             break; // Handshake successful
         }
         else {
             int err = SSL_get_error(ssl, ret);
             info_log("handshake in progress, %d, %s, %d, %d", ret, ERR_error_string(err, NULL), SSL_ERROR_SSL, SSL_ERROR_ZERO_RETURN);
             if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
                 // temporarely just continue.
                 continue;
             }
             else {
                 error_log("handshake error, returning");
                 // Handle handshake error
                 SSL_free(ssl);
                 return -1;
             }
         }
     }
     return 0;
 }

The curl command I used for testing and the verbose output

curl https://broken-bonds.com -v

* Trying 94.241.168.130:443...
* Connected to broken-bonds.com (94.241.168.130) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):

Just for a little context, why I don't just use bufferevent ssl init. I am currently rewriting our little project to depend less on libevent and SSL_do_handshake fails on the first attempt and I don't know why. res is 1, err is 1 which is SSL_ERROR_ZERO_RETURN if I'm not mistaken. https://www.openssl.org/docs/manmaster/man3/SSL_get_error.html

The code below works just fine and works nicely, so i don't think it's a problem with context, certs or network and honesty I'm stuck, I'm doing this alike to the libevent impl.

void acceptcb(evconnlistener listener, int fd,sockaddr addr, int addrlen, void arg) {
         auto server_dt = (server_data)arg;
         http_session_data session_data = new http_session_data(server_dt->app_ctx, server_dt->endpoint_handler, addr, addrlen);

         int val = 1;
         SSL *ssl = create_ssl(server_dt->app_ctx->ssl_ctx);
         setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
         bufferevent *bev = bufferevent_openssl_socket_new(
             server_dt->app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
             BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
         bufferevent_enable(bev, EV_READ | EV_WRITE);

         ssl = bufferevent_openssl_get_ssl(bev);

         bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);


 #if DEBUG_EXTENDED_INFO
         printf("acceptcb \tSSL_in_init: %d, SSL_in_before: %d, SSL_is_init_finished: %d, SSL_in_connect_init: %d, SSL_in_accept_init: %d, SSL_get_state: %d\n",
             SSL_in_init(ssl), SSL_in_before(ssl), SSL_is_init_finished(ssl), SSL_in_connect_init(ssl), SSL_in_accept_init(ssl), SSL_get_state(ssl));
         char client_ip[INET6_ADDRSTRLEN];
         int client_port;
         if (addr->sa_family == AF_INET) {
             struct sockaddr_in *s = (struct sockaddr_in *)addr;
             inet_ntop(AF_INET, &s->sin_addr, client_ip, sizeof client_ip);
             client_port = ntohs(s->sin_port);
         }
         else { // AF_INET6
             struct sockaddr_in6 *s = (struct sockaddr_in6 *)addr;
             inet_ntop(AF_INET6, &s->sin6_addr, client_ip, sizeof client_ip);
             client_port = ntohs(s->sin6_port);
         }

         // Log the connection details
         printf("New connection accepted: FD=%d, IP=%s, Port=%d\n", fd, client_ip, client_port);
 #endif
     }
0

There are 0 best solutions below