#endif
ctx_options = SSL_CTX_set_options(ctx, opts);
- SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ long mode = SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ mode |= SSL_MODE_RELEASE_BUFFERS;
+#endif
+ SSL_CTX_set_mode(ctx, mode);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
SSL_CTX_set_info_callback(ctx, StaticSSLInfoCallback);
long setoptions = tag->getInt(ctxname + "setoptions");
long clearoptions = tag->getInt(ctxname + "clearoptions");
#ifdef SSL_OP_NO_COMPRESSION
- if (!tag->getBool("compression", true))
+ if (!tag->getBool("compression", false)) // Disable compression by default
setoptions |= SSL_OP_NO_COMPRESSION;
#endif
- if (!tag->getBool("sslv3", true))
+ if (!tag->getBool("sslv3", false)) // Disable SSLv3 by default
setoptions |= SSL_OP_NO_SSLv3;
if (!tag->getBool("tlsv1", true))
setoptions |= SSL_OP_NO_TLSv1;
bool AllowRenegotiation() const { return allowrenego; }
unsigned int GetOutgoingRecordSize() const { return outrecsize; }
};
+
+ namespace BIOMethod
+ {
+ static int create(BIO* bio)
+ {
+ bio->init = 1;
+ return 1;
+ }
+
+ static int destroy(BIO* bio)
+ {
+ // XXX: Dummy function to avoid a memory leak in OpenSSL.
+ // The memory leak happens in BIO_free() (bio_lib.c) when the destroy func of the BIO is NULL.
+ // This is fixed in OpenSSL but some distros still ship the unpatched version hence we provide this workaround.
+ return 1;
+ }
+
+ static long ctrl(BIO* bio, int cmd, long num, void* ptr)
+ {
+ if (cmd == BIO_CTRL_FLUSH)
+ return 1;
+ return 0;
+ }
+
+ static int read(BIO* bio, char* buf, int len);
+ static int write(BIO* bio, const char* buf, int len);
+ }
}
+static BIO_METHOD biomethods =
+{
+ (100 | BIO_TYPE_SOURCE_SINK),
+ "inspircd",
+ OpenSSL::BIOMethod::write,
+ OpenSSL::BIOMethod::read,
+ NULL, // puts
+ NULL, // gets
+ OpenSSL::BIOMethod::ctrl,
+ OpenSSL::BIOMethod::create,
+ OpenSSL::BIOMethod::destroy, // destroy, does nothing, see function body for more info
+ NULL // callback_ctrl
+};
+
static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
{
/* XXX: This will allow self signed certificates.
// The other side is trying to renegotiate, kill the connection and change status
// to ISSL_NONE so CheckRenego() closes the session
status = ISSL_NONE;
- SocketEngine::Shutdown(SSL_get_fd(sess), 2);
+ BIO* bio = SSL_get_rbio(sess);
+ EventHandler* eh = static_cast<StreamSocket*>(bio->ptr);
+ SocketEngine::Shutdown(eh, 2);
}
}
, data_to_write(false)
, profile(sslprofile)
{
- if (sess == NULL)
- return;
- if (SSL_set_fd(sess, sock->GetFd()) == 0)
- throw ModuleException("Can't set fd with SSL_set_fd: " + ConvToStr(sock->GetFd()));
+ // Create BIO instance and store a pointer to the socket in it which will be used by the read and write functions
+ BIO* bio = BIO_new(&biomethods);
+ bio->ptr = sock;
+ SSL_set_bio(sess, bio, bio);
SSL_set_ex_data(sess, exdataindex, this);
sock->AddIOHook(this);
hook->SSLInfoCallback(where, rc);
}
+static int OpenSSL::BIOMethod::write(BIO* bio, const char* buffer, int size)
+{
+ BIO_clear_retry_flags(bio);
+
+ StreamSocket* sock = static_cast<StreamSocket*>(bio->ptr);
+ if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK)
+ {
+ // Writes blocked earlier, don't retry syscall
+ BIO_set_retry_write(bio);
+ return -1;
+ }
+
+ int ret = SocketEngine::Send(sock, buffer, size, 0);
+ if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError())))
+ {
+ // Blocked, set retry flag for OpenSSL
+ SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK);
+ BIO_set_retry_write(bio);
+ }
+
+ return ret;
+}
+
+static int OpenSSL::BIOMethod::read(BIO* bio, char* buffer, int size)
+{
+ BIO_clear_retry_flags(bio);
+
+ StreamSocket* sock = static_cast<StreamSocket*>(bio->ptr);
+ if (sock->GetEventMask() & FD_READ_WILL_BLOCK)
+ {
+ // Reads blocked earlier, don't retry syscall
+ BIO_set_retry_read(bio);
+ return -1;
+ }
+
+ int ret = SocketEngine::Recv(sock, buffer, size, 0);
+ if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError())))
+ {
+ // Blocked, set retry flag for OpenSSL
+ SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK);
+ BIO_set_retry_read(bio);
+ }
+
+ return ret;
+}
+
class OpenSSLIOHookProvider : public refcountbase, public IOHookProvider
{
reference<OpenSSL::Profile> profile;