diff options
Diffstat (limited to 'src/libmowgli/vio/vio_openssl.c')
-rw-r--r-- | src/libmowgli/vio/vio_openssl.c | 200 |
1 files changed, 137 insertions, 63 deletions
diff --git a/src/libmowgli/vio/vio_openssl.c b/src/libmowgli/vio/vio_openssl.c index 75c83e4..d492c9f 100644 --- a/src/libmowgli/vio/vio_openssl.c +++ b/src/libmowgli/vio/vio_openssl.c @@ -30,28 +30,28 @@ #ifdef HAVE_OPENSSL -typedef struct { +typedef struct +{ SSL *ssl_handle; SSL_CTX *ssl_context; mowgli_vio_ssl_settings_t settings; } mowgli_ssl_connection_t; -static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); -static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog); -static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio); static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection); -static int mowgli_vio_openssl_read(mowgli_vio_t *vio, void *buffer, size_t len); -static int mowgli_vio_openssl_write(mowgli_vio_t *vio, const void *buffer, size_t len); static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len); -static int mowgli_vio_openssl_close(mowgli_vio_t *vio); static mowgli_heap_t *ssl_heap = NULL; static bool openssl_init = false; -int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings) +static mowgli_vio_ops_t *openssl_ops = NULL; + +int +mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings, mowgli_vio_ops_t *ops) { - mowgli_ssl_connection_t *connection; + mowgli_ssl_connection_t *connection; + + return_val_if_fail(vio, -255); if (!ssl_heap) ssl_heap = mowgli_heap_create(sizeof(mowgli_ssl_connection_t), 64, BH_NOW); @@ -65,13 +65,28 @@ int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *sett /* Greatest compat without being terribly insecure */ connection->settings.ssl_version = MOWGLI_VIO_SSLFLAGS_SSLV3; + if (ops == NULL) + { + if (!openssl_ops) + { + openssl_ops = mowgli_alloc(sizeof(mowgli_vio_ops_t)); + memcpy(openssl_ops, &mowgli_vio_default_ops, sizeof(mowgli_vio_ops_t)); + } + + vio->ops = openssl_ops; + } + else + { + vio->ops = ops; + } + /* Change ops */ - mowgli_vio_set_op(vio, connect, mowgli_vio_openssl_connect); - mowgli_vio_set_op(vio, read, mowgli_vio_openssl_read); - mowgli_vio_set_op(vio, write, mowgli_vio_openssl_write); - mowgli_vio_set_op(vio, close, mowgli_vio_openssl_close); - mowgli_vio_set_op(vio, accept, mowgli_vio_openssl_accept); - mowgli_vio_set_op(vio, listen, mowgli_vio_openssl_listen); + mowgli_vio_ops_set_op(vio->ops, connect, mowgli_vio_openssl_default_connect); + mowgli_vio_ops_set_op(vio->ops, read, mowgli_vio_openssl_default_read); + mowgli_vio_ops_set_op(vio->ops, write, mowgli_vio_openssl_default_write); + mowgli_vio_ops_set_op(vio->ops, close, mowgli_vio_openssl_default_close); + mowgli_vio_ops_set_op(vio->ops, accept, mowgli_vio_openssl_default_accept); + mowgli_vio_ops_set_op(vio->ops, listen, mowgli_vio_openssl_default_listen); /* SSL setup */ if (!openssl_init) @@ -87,27 +102,39 @@ int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *sett } /* Returns void so they can be stubs */ -void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) { + return_val_if_fail(vio, NULL); mowgli_ssl_connection_t *connection = vio->privdata; return connection->ssl_handle; } -void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) { + return_val_if_fail(vio, NULL); mowgli_ssl_connection_t *connection = vio->privdata; return connection->ssl_context; } -static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) +int +mowgli_vio_openssl_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) { - vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; + const int fd = mowgli_vio_getfd(vio); + + return_val_if_fail(fd != -1, -255); + mowgli_ssl_connection_t *connection = vio->privdata; - if (connect(vio->fd, (struct sockaddr *)&addr->addr, addr->addrlen) < 0) + vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; + + if (connect(fd, (struct sockaddr *) &addr->addr, addr->addrlen) < 0) { if (!mowgli_eventloop_ignore_errno(errno)) + { return mowgli_vio_err_errcode(vio, strerror, errno); + } else { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, true); @@ -128,11 +155,16 @@ static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t * return mowgli_vio_openssl_client_handshake(vio, connection); } -static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) +int +mowgli_vio_openssl_default_listen(mowgli_vio_t *vio, int backlog) { - vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN; + return_val_if_fail(vio, -255); + mowgli_ssl_connection_t *connection = vio->privdata; const SSL_METHOD *method; + const int fd = mowgli_vio_getfd(vio); + + vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN; switch (connection->settings.ssl_version) { @@ -148,21 +180,24 @@ static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) method = TLSv1_server_method(); break; default: + /* Compat method */ method = SSLv23_server_method(); } - - connection->ssl_context = SSL_CTX_new((SSL_METHOD *)method); + + connection->ssl_context = SSL_CTX_new((SSL_METHOD *) method); + if (connection->ssl_context == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); connection->ssl_handle = SSL_new(connection->ssl_context); + if (connection->ssl_handle == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); SSL_set_accept_state(connection->ssl_handle); SSL_CTX_set_options(connection->ssl_context, SSL_OP_SINGLE_DH_USE); - + if (connection->settings.password_func) { SSL_CTX_set_default_passwd_cb(connection->ssl_context, connection->settings.password_func); @@ -175,10 +210,10 @@ static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) if (SSL_CTX_use_PrivateKey_file(connection->ssl_context, connection->settings.privatekey_path, SSL_FILETYPE_PEM) != 1) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); - if (listen(vio->fd, backlog) != 0) + if (listen(fd, backlog) != 0) return mowgli_vio_err_errcode(vio, strerror, errno); - if (!SSL_set_fd(connection->ssl_handle, vio->fd)) + if (!SSL_set_fd(connection->ssl_handle, fd)) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, true); @@ -187,10 +222,15 @@ static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) return 0; } -static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) +int +mowgli_vio_openssl_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) { - int fd; + const int fd = mowgli_vio_getfd(vio); + int afd; int ret; + + return_val_if_fail(fd != -1, -255); + mowgli_ssl_connection_t *connection = vio->privdata; mowgli_ssl_connection_t *newconnection; @@ -204,7 +244,7 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return mowgli_vio_error(vio); } - if ((fd = accept(vio->fd, (struct sockaddr *)&newvio->addr.addr, &(newvio->addr.addrlen))) < 0) + if ((afd = accept(fd, (struct sockaddr *) &newvio->addr.addr, &(newvio->addr.addrlen))) < 0) { if (!mowgli_eventloop_ignore_errno(errno)) return mowgli_vio_err_errcode(vio, strerror, errno); @@ -212,14 +252,14 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return 0; } - newvio->fd = fd; + newvio->io.fd = afd; - mowgli_vio_openssl_setssl(newvio, &connection->settings); + mowgli_vio_openssl_setssl(newvio, &connection->settings, vio->ops); newconnection = newvio->privdata; newconnection->ssl_context = connection->ssl_context; newconnection->ssl_handle = SSL_new(newconnection->ssl_context); - - if (!SSL_set_fd(newconnection->ssl_handle, fd)) + + if (!SSL_set_fd(newconnection->ssl_handle, afd)) return mowgli_vio_err_sslerrcode(newvio, ERR_get_error()); if ((ret = SSL_accept(newconnection->ssl_handle)) != 1) @@ -230,9 +270,11 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) { case SSL_ERROR_WANT_READ: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + MOWGLI_VIO_SETREAD(vio) return 0; case SSL_ERROR_WANT_WRITE: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) return 0; case SSL_ERROR_ZERO_RETURN: return 0; @@ -243,7 +285,7 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) break; } - if(err > 0) + if (err > 0) { errno = EIO; return mowgli_vio_err_errcode(vio, strerror, errno); @@ -259,8 +301,10 @@ static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) return 0; } -static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection) +static int +mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection) { + const int fd = mowgli_vio_getfd(vio); int ret; const SSL_METHOD *method; @@ -280,41 +324,56 @@ static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_con method = TLSv1_client_method(); break; default: + /* Compat method */ method = SSLv23_client_method(); } /* Cast is to eliminate an excessively bogus warning on old OpenSSL --Elizacat */ - connection->ssl_context = SSL_CTX_new((SSL_METHOD *)method); + connection->ssl_context = SSL_CTX_new((SSL_METHOD *) method); + if (connection->ssl_context == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); connection->ssl_handle = SSL_new(connection->ssl_context); + if (connection->ssl_handle == NULL) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); - + SSL_set_connect_state(connection->ssl_handle); - - if (!SSL_set_fd(connection->ssl_handle, vio->fd)) + + if (!SSL_set_fd(connection->ssl_handle, fd)) return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); - /* XXX not what we want for blocking sockets if they're in use! */ - SSL_CTX_set_mode(connection->ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE); + if (vio->eventloop) + SSL_CTX_set_mode(connection->ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE); if ((ret = SSL_connect(connection->ssl_handle)) != 1) { - int err = SSL_get_error(connection->ssl_handle, ret); + unsigned long err = SSL_get_error(connection->ssl_handle, ret); + if (err == SSL_ERROR_WANT_READ) + { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + MOWGLI_VIO_SETREAD(vio) + } else if (err == SSL_ERROR_WANT_WRITE) + { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) + } else if (err == SSL_ERROR_WANT_CONNECT) { mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, true); return 0; } else + { return mowgli_vio_err_sslerrcode(vio, err); + } + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSSLCONNECTING, false); + return 0; } /* Connected */ @@ -324,22 +383,25 @@ static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_con return 0; } -#define MOWGLI_VIO_SSL_DOREAD true -#define MOWGLI_VIO_SSL_DOWRITE false +# define MOWGLI_VIO_SSL_DOREAD true +# define MOWGLI_VIO_SSL_DOWRITE false -static int mowgli_vio_openssl_read(mowgli_vio_t *vio, void *buffer, size_t len) +int +mowgli_vio_openssl_default_read(mowgli_vio_t *vio, void *buffer, size_t len) { vio->error.op = MOWGLI_VIO_ERR_OP_READ; return mowgli_openssl_read_or_write(MOWGLI_VIO_SSL_DOREAD, vio, buffer, NULL, len); } -static int mowgli_vio_openssl_write(mowgli_vio_t *vio, const void *buffer, size_t len) +int +mowgli_vio_openssl_default_write(mowgli_vio_t *vio, const void *buffer, size_t len) { vio->error.op = MOWGLI_VIO_ERR_OP_WRITE; return mowgli_openssl_read_or_write(MOWGLI_VIO_SSL_DOWRITE, vio, NULL, buffer, len); } -static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len) +static int +mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len) { mowgli_ssl_connection_t *connection = vio->privdata; int ret; @@ -353,10 +415,15 @@ static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *read return_val_if_fail(connection->ssl_handle != NULL, -1); - if(read) - ret = (int)SSL_read(connection->ssl_handle, readbuf, len); + if (read) + { + ret = (int) SSL_read(connection->ssl_handle, readbuf, len); + } else - ret = (int)SSL_write(connection->ssl_handle, writebuf, len); + { + ret = (int) SSL_write(connection->ssl_handle, writebuf, len); + MOWGLI_VIO_UNSETWRITE(vio) + } if (ret < 0) { @@ -364,32 +431,34 @@ static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *read { case SSL_ERROR_WANT_READ: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + MOWGLI_VIO_SETREAD(vio) return 0; case SSL_ERROR_WANT_WRITE: mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + MOWGLI_VIO_SETWRITE(vio) return 0; case SSL_ERROR_ZERO_RETURN: return 0; case SSL_ERROR_SYSCALL: - if((err = ERR_get_error()) == 0) + + if ((err = ERR_get_error()) == 0) { vio->error.type = MOWGLI_VIO_ERR_REMOTE_HANGUP; mowgli_strlcpy(vio->error.string, "Remote host closed the socket", sizeof(vio->error.string)); - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); - mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, true); - + MOWGLI_VIO_SET_CLOSED(vio); + return mowgli_vio_error(vio); } break; - + default: err = ERR_get_error(); break; } - if(err > 0) + if (err > 0) { errno = EIO; return mowgli_vio_err_errcode(vio, strerror, errno); @@ -405,8 +474,10 @@ static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *read return ret; } -static int mowgli_vio_openssl_close(mowgli_vio_t *vio) +int +mowgli_vio_openssl_default_close(mowgli_vio_t *vio) { + const int fd = mowgli_vio_getfd(vio); mowgli_ssl_connection_t *connection = vio->privdata; return_val_if_fail(connection->ssl_handle != NULL, -1); @@ -419,29 +490,32 @@ static int mowgli_vio_openssl_close(mowgli_vio_t *vio) MOWGLI_VIO_SET_CLOSED(vio); - close(vio->fd); + /* FIXME - doesn't verify a proper SSL shutdown! */ + close(fd); return 0; } #else -int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings) +int +mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings, mowgli_vio_ops_t *ops) { mowgli_log("OpenSSL requested on a VIO object, but mowgli was built without OpenSSL support..."); return -1; } -void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) { mowgli_log("Cannot get VIO SSL handle as libmowgli was built without OpenSSL support"); return NULL; } -void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) +void * +mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) { mowgli_log("Cannot get VIO SSL context as libmowgli was built without OpenSSL support"); return NULL; } #endif - |