X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fextra%2Fm_ssl_gnutls.cpp;h=f8dc85659b1a82c927faef5d3f691c74ab968047;hb=2972f1ec3fbecb70f7ad7f4f605fb5b9264e8816;hp=ad182e826c16524b5de5d4029c067ce0fb0820fd;hpb=19eb420281670348532fdd58f5fe757d5413faf7;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index ad182e826..f8dc85659 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -70,7 +70,7 @@ typedef gnutls_certificate_credentials_t gnutls_certificate_credentials; typedef gnutls_dh_params_t gnutls_dh_params; #endif -enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED }; +enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_HANDSHAKEN }; #if INSPIRCD_GNUTLS_HAS_VERSION(2, 12, 0) #define GNUTLS_NEW_CERT_CALLBACK_API @@ -628,7 +628,8 @@ class GnuTLSIOHook : public SSLIOHook status = ISSL_NONE; } - bool Handshake(StreamSocket* user) + // Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed + int Handshake(StreamSocket* user) { int ret = gnutls_handshake(this->sess); @@ -637,28 +638,27 @@ class GnuTLSIOHook : public SSLIOHook if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) { // Handshake needs resuming later, read() or write() would have blocked. + this->status = ISSL_HANDSHAKING; if (gnutls_record_get_direction(this->sess) == 0) { // gnutls_handshake() wants to read() again. - this->status = ISSL_HANDSHAKING_READ; SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); } else { // gnutls_handshake() wants to write() again. - this->status = ISSL_HANDSHAKING_WRITE; SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE); } + + return 0; } else { user->SetError("Handshake Failed - " + std::string(gnutls_strerror(ret))); CloseSession(); - this->status = ISSL_CLOSING; + return -1; } - - return false; } else { @@ -670,7 +670,7 @@ class GnuTLSIOHook : public SSLIOHook // Finish writing, if any left SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE); - return true; + return 1; } } @@ -778,6 +778,22 @@ info_done_dealloc: gnutls_x509_crt_deinit(cert); } + // Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error + int PrepareIO(StreamSocket* sock) + { + if (status == ISSL_HANDSHAKEN) + return 1; + else if (status == ISSL_HANDSHAKING) + { + // The handshake isn't finished, try to finish it + return Handshake(sock); + } + + CloseSession(); + sock->SetError("No SSL session"); + return -1; + } + static const char* UnknownIfNULL(const char* str) { return str ? str : "UNKNOWN"; @@ -874,28 +890,12 @@ info_done_dealloc: int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE { - if (!this->sess) - { - CloseSession(); - user->SetError("No SSL session"); - return -1; - } - - if (this->status == ISSL_HANDSHAKING_READ || this->status == ISSL_HANDSHAKING_WRITE) - { - // The handshake isn't finished, try to finish it. - - if (!Handshake(user)) - { - if (this->status != ISSL_CLOSING) - return 0; - return -1; - } - } + // Finish handshake if needed + int prepret = PrepareIO(user); + if (prepret <= 0) + return prepret; // If we resumed the handshake then this->status will be ISSL_HANDSHAKEN. - - if (this->status == ISSL_HANDSHAKEN) { GnuTLS::DataReader reader(sess); int ret = reader.ret(); @@ -921,33 +921,18 @@ info_done_dealloc: return -1; } } - else if (this->status == ISSL_CLOSING) - return -1; - - return 0; } int OnStreamSocketWrite(StreamSocket* user, std::string& sendq) CXX11_OVERRIDE { - if (!this->sess) - { - CloseSession(); - user->SetError("No SSL session"); - return -1; - } - - if (this->status == ISSL_HANDSHAKING_WRITE || this->status == ISSL_HANDSHAKING_READ) - { - // The handshake isn't finished, try to finish it. - Handshake(user); - if (this->status != ISSL_CLOSING) - return 0; - return -1; - } + // Finish handshake if needed + int prepret = PrepareIO(user); + if (prepret <= 0) + return prepret; + // Session is ready for transferring application data int ret = 0; - if (this->status == ISSL_HANDSHAKEN) { ret = gnutls_record_send(this->sess, sendq.data(), sendq.length()); @@ -974,8 +959,6 @@ info_done_dealloc: return -1; } } - - return 0; } void TellCiphersAndFingerprint(LocalUser* user)