blob: bc11fa4d860012772d44d215492c7736e5134159 [file] [log] [blame]
#include "config.h"
#include "flood_profile.h"
#include "flood_net.h"
#include "flood_net_ssl.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <apr_portable.h>
struct ssl_socket_t {
SSL_CTX *ssl_context;
SSL *ssl_connection;
apr_socket_t *socket;
apr_pollfd_t *poll;
};
apr_status_t ssl_init_socket(apr_pool_t *pool)
{
SSL_library_init();
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
ERR_load_crypto_strings();
RAND_load_file("/home/jerenkrantz/.rnd", -1);
return APR_SUCCESS;
}
void ssl_read_socket_handshake(ssl_socket_t *s);
ssl_socket_t* ssl_open_socket(apr_pool_t *pool, request_t *r)
{
apr_os_sock_t ossock;
int e, sslError;
ssl_socket_t *ssl_socket = apr_pcalloc(pool, sizeof(ssl_socket_t));
/* Open our TCP-based connection */
ssl_socket->socket = open_socket(pool, r);
if (!ssl_socket->socket)
return NULL;
/* Get the native OS socket. */
apr_os_sock_get(&ossock, ssl_socket->socket);
/* Create a local context */
ssl_socket->ssl_context = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_options(ssl_socket->ssl_context, SSL_OP_ALL);
SSL_CTX_set_options(ssl_socket->ssl_context, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_default_verify_paths(ssl_socket->ssl_context);
/* Initialize the SSL connection */
ssl_socket->ssl_connection = SSL_new(ssl_socket->ssl_context);
SSL_set_connect_state(ssl_socket->ssl_connection);
/* Set the descriptors */
SSL_set_fd(ssl_socket->ssl_connection, ossock);
e = SSL_connect(ssl_socket->ssl_connection);
apr_poll_setup(&ssl_socket->poll, 1, pool);
apr_poll_socket_add(ssl_socket->poll, ssl_socket->socket, APR_POLLIN);
if (e)
{
sslError = SSL_get_error(ssl_socket->ssl_connection, e);
switch (sslError)
{
case SSL_ERROR_NONE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
/* Treat as okay. */
break;
default:
ERR_print_errors_fp(stderr);
return NULL;
}
}
return ssl_socket;
}
/* close down TCP socket */
void ssl_close_socket(ssl_socket_t *s)
{
SSL_free(s->ssl_connection);
SSL_CTX_free(s->ssl_context);
/* s->poll can be cleaned up when our pool dies. */
apr_socket_close(s->socket);
}
apr_status_t ssl_read_socket(ssl_socket_t *s, char *buf, int *buflen)
{
apr_status_t e;
int sslError, socketsRead;
/* Wait until there is something to read. */
socketsRead = 1;
e = apr_poll(s->poll, &socketsRead, LOCAL_SOCKET_TIMEOUT);
e = SSL_read(s->ssl_connection, buf, *buflen);
sslError = SSL_get_error(s->ssl_connection, e);
switch (sslError)
{
case SSL_ERROR_NONE:
*buflen = e;
break;
case SSL_ERROR_WANT_READ:
ssl_read_socket(s, buf, buflen);
break;
case SSL_ERROR_ZERO_RETURN: /* Treat as error. Peer closed connection. */
case SSL_ERROR_WANT_WRITE: /* Technically, not an error. */
default:
ERR_print_errors_fp(stderr);
return APR_EGENERAL;
}
return APR_SUCCESS;
}
void ssl_read_socket_handshake(ssl_socket_t *s)
{
char buf[1];
int buflen = 1;
/* Wait until there is something to read. */
int socketsRead = 1;
apr_status_t e;
e = apr_poll(s->poll, &socketsRead, LOCAL_SOCKET_TIMEOUT);
e = SSL_read(s->ssl_connection, buf, buflen);
}
/* Write to the socket */
apr_status_t ssl_write_socket(ssl_socket_t *s, request_t *r)
{
apr_status_t e;
int sslError;
/* Returns an error. */
e = SSL_write(s->ssl_connection, r->rbuf, r->rbufsize);
sslError = SSL_get_error(s->ssl_connection, e);
switch (sslError)
{
case SSL_ERROR_NONE:
break;
case SSL_ERROR_WANT_READ:
ssl_read_socket_handshake(s);
ssl_write_socket(s, r);
break;
case SSL_ERROR_WANT_WRITE:
break;
default:
ERR_print_errors_fp(stderr);
return APR_EGENERAL;
}
return APR_SUCCESS;
}