0
votes

I try to make a SSL connection, until the SSL_handshake. After the handshake, there is nothing to read from the socket. There is something written to the socket from the client so I expect a response of the server. The socket is connected the whole process, so I don't know what's wrong. The code is displayed under and I have placed comments where the process fails.


struct ssl_information {
    int connected;
    int sock;

    BIO *bio_read;
    BIO *bio_write;

    SSL *ssl;
    SSL_CTX *ctx;
};

void ssl_connection_init()
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void ssl_disconnect(struct ssl_information *ssl)
{
    if(!ssl->connected) return;

    if(ssl->ctx) SSL_CTX_free(ssl->ctx);

    if(ssl->ssl) {
        SSL_shutdown(ssl->ssl);
        SSL_free(ssl->ssl);
    }

    close(ssl->sock);
    ssl->connected = 0;
}

int ssl_read_socket(struct ssl_information *ssl)
{
    int rc;
    unsigned char buffer[4096];

    rc = read(ssl->sock, buffer, sizeof(buffer)); \\reads nothing on the last call

    if(rc == 0 || rc == -1) return 0;

    BIO_write(ssl->bio_read, buffer, rc);

    return 1;
}

int ssl_write_socket(struct ssl_information *ssl)
{
    int rc;
    unsigned char buffer[4096];

    rc = BIO_read(ssl->bio_write, buffer, sizeof(buffer));

    if(write(ssl->sock, buffer, rc) != rc) return 0;

    return 1;
}

int tcp_connection(char *ip, int port)
{
    int flags, rc, sock;
    struct sockaddr_in address;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock == -1) return -1;

    flags = fcntl(sock, F_GETFL);
    rc = fcntl(sock, F_SETFL, flags | O_NONBLOCK);

    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(ip);
    address.sin_port = htons(port);

    connect(sock, (struct sockaddr *)&address, sizeof(address));

    return sock;
}

struct ssl_information ssl_connection(char *ip, int port)
{
    fd_set read_file_descriptor, write_file_descriptor;
    static struct ssl_information ssl;

    ssl.sock = tcp_connection(ip, port);
    if(ssl.sock == -1) {
        ssl.connected = 0;
        return ssl;
    }

    ssl.bio_read = BIO_new(BIO_s_mem());
    ssl.bio_write = BIO_new(BIO_s_mem());

    ssl.ctx = SSL_CTX_new(TLS_method());
    ssl.ssl = SSL_new(ssl.ctx);

    SSL_set_connect_state(ssl.ssl);
    SSL_set_bio(ssl.ssl, ssl.bio_read, ssl.bio_write);


    while(1) {
        FD_ZERO(&read_file_descriptor);
        FD_ZERO(&write_file_descriptor);

        if(SSL_in_init(ssl.ssl)) SSL_do_handshake(ssl.ssl);

        if(SSL_is_init_finished(ssl.ssl)) break;

        FD_SET(ssl.sock, &read_file_descriptor);

        if(BIO_pending(ssl.bio_write)) FD_SET(ssl.sock, &write_file_descriptor);

        switch(select(FD_SETSIZE, &read_file_descriptor, &write_file_descriptor, 0, 0)) {
            case -1:
            case 0:
                printf("Failed to monitor socket!\n");
                ssl_disconnect(&ssl);
                return ssl;

            default:
                if(FD_ISSET(ssl.sock, &read_file_descriptor)) {
                    if(!ssl_read_socket(&ssl)) {
                        printf("Failed to read from socket!\n");
                        ssl_disconnect(&ssl);
                        return ssl;
                    }
                }
                if(FD_ISSET(ssl.sock, &write_file_descriptor)) {
                    if(!ssl_write_socket(&ssl)) {
                        printf("Failed to write to socket!\n");
                        ssl_disconnect(&ssl);
                        return ssl;
                    }
                }
        }
    }

    ssl.connected = 1;

    return ssl;
}

int main()
{
    struct ssl_information ssl;
    char response[4096];

    ssl = ssl_connection(ip, port);

    if(!ssl.connected) {
        ssl_disconnect(&ssl);
        return 0;
    }

    BIO_write(ssl.bio_write, message, sizeof(message)); //message is of course set to something
    ssl_write_socket(&ssl);

    ssl_read_socket(&ssl); \\returns 0
    BIO_read(ssl.bio_read, response, sizeof(response)); \\ reads nothing
    printf("response: %s\n", response);

    return 1;
}


"After the handshake, there is nothing to read from the socket." Does the remote part sends anything? If neither of the two endpoints initiate the conversation, then nothing will happen at the application data step, after the full TLS handshake is finished. It is up to the protocol defining the exchange to specify who speaks first. Sometimes it is the client side (ex: HTTP) and sometimes it is the server side (ex: SMTP, FTP). - Patrick Mevzek
The client speaks first. The function ssl_write_socket is called after the handshake. - jason