]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
m_ssl_openssl Add compile time option that allows disabling renegotiations
authorAttila Molnar <attilamolnar@hush.com>
Fri, 17 Oct 2014 16:46:47 +0000 (18:46 +0200)
committerAttila Molnar <attilamolnar@hush.com>
Mon, 20 Oct 2014 19:00:26 +0000 (21:00 +0200)
src/modules/extra/m_ssl_openssl.cpp

index 737dab91417cf93f3f85356f2ce8fef74271200c..02f44f2f13cf8b5cd50a116f606821dcd9a24b3d 100644 (file)
 /* $NoPedantic */
 
 
+class ModuleSSLOpenSSL;
+
 enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
 
 static bool SelfSigned = false;
 
+#ifdef INSPIRCD_OPENSSL_ENABLE_RENEGO_DETECTION
+static ModuleSSLOpenSSL* opensslmod = NULL;
+#endif
+
 char* get_error()
 {
        return ERR_error_string(ERR_get_error(), NULL);
@@ -173,10 +179,40 @@ class ModuleSSLOpenSSL : public Module
        }
 #endif
 
+#ifdef INSPIRCD_OPENSSL_ENABLE_RENEGO_DETECTION
+       static void SSLInfoCallback(const SSL* ssl, int where, int rc)
+       {
+               int fd = SSL_get_fd(const_cast<SSL*>(ssl));
+               issl_session& session = opensslmod->sessions[fd];
+
+               if ((where & SSL_CB_HANDSHAKE_START) && (session.status == ISSL_OPEN))
+               {
+                       // The other side is trying to renegotiate, kill the connection and change status
+                       // to ISSL_NONE so CheckRenego() closes the session
+                       session.status = ISSL_NONE;
+                       ServerInstance->SE->Shutdown(fd, 2);
+               }
+       }
+
+       bool CheckRenego(StreamSocket* sock, issl_session* session)
+       {
+               if (session->status != ISSL_NONE)
+                       return true;
+
+               ServerInstance->Logs->Log("m_ssl_openssl", DEBUG, "Session %p killed, attempted to renegotiate", (void*)session->sess);
+               CloseSession(session);
+               sock->SetError("Renegotiation is not allowed");
+               return false;
+       }
+#endif
+
  public:
 
        ModuleSSLOpenSSL() : iohook(this, "ssl/openssl", SERVICE_IOHOOK)
        {
+#ifdef INSPIRCD_OPENSSL_ENABLE_RENEGO_DETECTION
+               opensslmod = this;
+#endif
                sessions = new issl_session[ServerInstance->SE->GetMaxFds()];
 
                /* Global SSL library initialization*/
@@ -235,6 +271,20 @@ class ModuleSSLOpenSSL : public Module
 
                ConfigTag* Conf = ServerInstance->Config->ConfValue("openssl");
 
+#ifdef INSPIRCD_OPENSSL_ENABLE_RENEGO_DETECTION
+               // Set the callback if we are not allowing renegotiations, unset it if we do
+               if (Conf->getBool("renegotiation", true))
+               {
+                       SSL_CTX_set_info_callback(ctx, NULL);
+                       SSL_CTX_set_info_callback(clictx, NULL);
+               }
+               else
+               {
+                       SSL_CTX_set_info_callback(ctx, SSLInfoCallback);
+                       SSL_CTX_set_info_callback(clictx, SSLInfoCallback);
+               }
+#endif
+
                if (Conf->getBool("showports", true))
                {
                        sslports = Conf->getString("advertisedports");
@@ -533,6 +583,11 @@ class ModuleSSLOpenSSL : public Module
                        size_t bufsiz = ServerInstance->Config->NetBufferSize;
                        int ret = SSL_read(session->sess, buffer, bufsiz);
 
+#ifdef INSPIRCD_OPENSSL_ENABLE_RENEGO_DETECTION
+                       if (!CheckRenego(user, session))
+                               return -1;
+#endif
+
                        if (ret > 0)
                        {
                                recvq.append(buffer, ret);
@@ -601,6 +656,12 @@ class ModuleSSLOpenSSL : public Module
                {
                        ERR_clear_error();
                        int ret = SSL_write(session->sess, buffer.data(), buffer.size());
+
+#ifdef INSPIRCD_OPENSSL_ENABLE_RENEGO_DETECTION
+                       if (!CheckRenego(user, session))
+                               return -1;
+#endif
+
                        if (ret == (int)buffer.length())
                        {
                                session->data_to_write = false;