diff options
Diffstat (limited to 'vio/VioSSL.cc')
-rw-r--r-- | vio/VioSSL.cc | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/vio/VioSSL.cc b/vio/VioSSL.cc new file mode 100644 index 00000000000..a8efacf912f --- /dev/null +++ b/vio/VioSSL.cc @@ -0,0 +1,292 @@ +/* +** Virtual I/O library for SSL wrapper +** Written by Andrei Errapart <andreie@no.spam.ee> +*/ + +/* + * This file has some huge DBUG_ statements. Boy, this is silly... + */ + +#include "vio-global.h" +#ifdef VIO_HAVE_OPENSSL +#include <assert.h> +#include <netinet/in.h> +#include <openssl/x509.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/pem.h> + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +VIO_NS_BEGIN + +#define this_ssl_con my_static_cast(SSL*)(this->ssl_con_) +#define this_bio my_static_cast(BIO*)(this->bio_) +typedef char* dataptr_t; + +static void +report_errors() +{ + unsigned long l; + const char* file; + const char* data; + int line,flags; + DBUG_ENTER("VioSSLConnectorFd::report_errors"); + + while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) + { + char buf[200]; + DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf), + file,line,(flags&ERR_TXT_STRING)?data:"")) ; + } + DBUG_VOID_RETURN; +} + +//FIXME: duplicate code! +VioSSL::VioSSL(int fd, + vio_ptr ssl_context, + int state) + : bio_(0), ssl_con_(0), open_(false), sd_(new VioSocket(fd)) +{ + DBUG_ENTER("VioSSL::VioSSL"); + DBUG_PRINT("enter", ("this=%p, fd=%d, ssl_context=%p, state=%d", + this, fd, ssl_context, state)); + assert(fd!=0); + assert(ssl_context!=0); + assert(state==state_connect || state==state_accept); + + if (!init_bio_(fd, ssl_context, state, BIO_NOCLOSE)) + open_ = true; + DBUG_VOID_RETURN; +} + + +VioSSL::VioSSL(VioSocket* sd, + vio_ptr ssl_context, + int state) + :bio_(0), ssl_con_(0), open_(false), sd_(sd) +{ + DBUG_ENTER("VioSSL::VioSSL"); + DBUG_PRINT("enter", + ("this=%p, sd=%s, ssl_context=%p, state=%d", + this, sd ? sd->description() : "0", ssl_context, state)); + assert(sd != 0); + assert(ssl_context != 0); + assert(state == state_connect || state==state_accept); + + if (!init_bio_(sd->sd_, ssl_context, state, BIO_NOCLOSE)) + open_ = true; + DBUG_VOID_RETURN; +} + +VioSSL::~VioSSL() +{ + DBUG_ENTER("VioSSL::~VioSSL"); + DBUG_PRINT("enter", ("this=%p", this)); + if (ssl_con_!=0) + { + SSL_shutdown(this_ssl_con); + SSL_free(this_ssl_con); + } + if (sd_!=0) + delete sd_; + /* FIXME: no need to close bio? */ + /* + if (bio_!=0) + BIO_free(this_bio); + */ + DBUG_VOID_RETURN; +} + +bool +VioSSL::is_open() const +{ + return open_; +} + +int +VioSSL::read(vio_ptr buf, int size) +{ + int r; + DBUG_ENTER("VioSSL::read"); + DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size)); + assert(this_ssl_con != 0); + r = SSL_read(this_ssl_con, my_static_cast(dataptr_t)(buf), size); + if ( r< 0) + report_errors(); + DBUG_PRINT("exit", ("r=%d", r)); + DBUG_RETURN(r); +} + +int +VioSSL::write(const vio_ptr buf, int size) +{ + int r; + DBUG_ENTER("VioSSL::write"); + DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size)); + assert(this_ssl_con!=0); + r = SSL_write(this_ssl_con, my_static_cast(dataptr_t)(buf), size); + if (r<0) + report_errors(); + DBUG_PRINT("exit", ("r=%d", r)); + DBUG_RETURN(r); +} + +int +VioSSL::blocking(bool onoff) +{ + int r; + DBUG_ENTER("VioSSL::blocking"); + DBUG_PRINT("enter", ("this=%p, onoff=%s", this, onoff?"true":"false")); + r = sd_->blocking(onoff); + DBUG_PRINT("exit", ("r=%d", (int)r )); + DBUG_RETURN(r); +} + +bool +VioSSL::blocking() const +{ + bool r; + DBUG_ENTER("VioSSL::blocking"); + DBUG_PRINT("enter", ("this=%p", this)); + r = sd_->blocking(); + DBUG_PRINT("exit", ("r=%d", (int)r )); + DBUG_RETURN(r); +} + +int +VioSSL::fastsend(bool onoff) +{ + int r; + DBUG_ENTER("VioSSL::fastsend"); + DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff)); + r = sd_->fastsend(onoff); + DBUG_PRINT("exit", ("r=%d", (int)r )); + DBUG_RETURN(r); +} + +int VioSSL::keepalive(bool onoff) +{ + int r; + DBUG_ENTER("VioSSL::keepalive"); + DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff)); + r = sd_->keepalive(onoff); + DBUG_PRINT("exit", ("r=%d", int(r) )); + DBUG_RETURN(r); +} + +bool +VioSSL::fcntl() const +{ + bool r; + DBUG_ENTER("VioSSL::fcntl"); + DBUG_PRINT("enter", ("this=%p", this)); + r = sd_->fcntl(); + DBUG_PRINT("exit", ("r=%d", (int)r )); + DBUG_RETURN(r); +} + +bool +VioSSL::should_retry() const +{ + bool r; + DBUG_ENTER("VioSSL::should_retry"); + DBUG_PRINT("enter", ("this=%p", this)); + r = sd_->should_retry(); + DBUG_PRINT("exit", ("r=%d", (int)r )); + DBUG_RETURN(r); +} + +int +VioSSL::close() +{ + int r= -2; + DBUG_ENTER("VioSSL::close"); + DBUG_PRINT("enter", ("this=%p", this)); + if (ssl_con) + { + r = SSL_shutdown(this_ssl_con); + SSL_free(this_ssl_con); + ssl_con_ = 0; + BIO_free(this_bio); + bio_ = 0; + } + DBUG_PRINT("exit", ("r=%d", r)); + DBUG_RETURN(r); +} + +const char* +VioSSL::description() const +{ + return desc_; +} + +const char* +VioSSL::peer_addr() const +{ + if (sd_!=0) + return sd != 0 ? sd_->peer_addr() : ""; +} + +const char* +VioSSL::peer_name() const +{ + return sd != 0 ? sd_->peer_name() : ""; +} + +const char* +VioSSL::cipher_description() const +{ + return SSL_get_cipher_name(this_ssl_con); +} + + +int +VioSSL::init_bio_(int fd, + vio_ptr ssl_context, + int state, + int bio_flags) +{ + DBUG_ENTER("VioSSL::init_bio_"); + DBUG_PRINT("enter", + ("this=%p, fd=%p, ssl_context=%p, state=%d, bio_flags=%d", + this, fd, ssl_context, state, bio_flags)); + + + if (!(ssl_con_ = SSL_new(my_static_cast(SSL_CTX*)(ssl_context)))) + { + DBUG_PRINT("error", ("SSL_new failure")); + report_errors(); + DBUG_RETURN(-1); + } + if (!(bio_ = BIO_new_socket(fd, bio_flags))) + { + DBUG_PRINT("error", ("BIO_new_socket failure")); + report_errors(); + SSL_free(ssl_con_); + ssl_con_ =0; + DBUG_RETURN(-1); + } + SSL_set_bio(this_ssl_con, this_bio, this_bio); + switch(state) { + case state_connect: + SSL_set_connect_state(this_ssl_con); + break; + case state_accept: + SSL_set_accept_state(this_ssl_con); + break; + default: + assert(0); + } + sprintf(desc_, "VioSSL(%d)", fd); + ssl_cip_ = new SSL_CIPHER ; + DBUG_RETURN(0); +} + + +VIO_NS_END + +#endif /* VIO_HAVE_OPENSSL */ + |