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;
}