X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fextra%2Fm_ssl_mbedtls.cpp;h=83b9d05956c88100a7e1e068c21a97ef91ba3299;hb=6d3e316234f47468cd15bc9bdff66e2a76fa4cd6;hp=ec67d9787ca78ec60ddded113d207f3bdaaf744a;hpb=b0654ef6abd8d976fcbadce24ea350f7c420fe08;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/extra/m_ssl_mbedtls.cpp b/src/modules/extra/m_ssl_mbedtls.cpp index ec67d9787..83b9d0595 100644 --- a/src/modules/extra/m_ssl_mbedtls.cpp +++ b/src/modules/extra/m_ssl_mbedtls.cpp @@ -1,7 +1,9 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2016 Attila Molnar + * Copyright (C) 2020 Matt Schatz + * Copyright (C) 2016-2020 Sadie Powell + * Copyright (C) 2016-2017 Attila Molnar * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -18,6 +20,7 @@ /// $LinkerFlags: -lmbedtls +/// $PackageInfo: require_system("arch") mbedtls /// $PackageInfo: require_system("darwin") mbedtls /// $PackageInfo: require_system("debian" "9.0") libmbedtls-dev /// $PackageInfo: require_system("ubuntu" "16.04") libmbedtls-dev @@ -26,6 +29,17 @@ #include "inspircd.h" #include "modules/ssl.h" +// Fix warnings about the use of commas at end of enumerator lists on C++03. +#if defined __clang__ +# pragma clang diagnostic ignored "-Wc++11-extensions" +#elif defined __GNUC__ +# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) +# pragma GCC diagnostic ignored "-Wpedantic" +# else +# pragma GCC diagnostic ignored "-pedantic" +# endif +#endif + #include #include #include @@ -345,7 +359,7 @@ namespace mbedTLS } }; - class Profile : public refcountbase + class Profile { /** Name of this profile */ @@ -378,29 +392,71 @@ namespace mbedTLS */ const unsigned int outrecsize; - Profile(const std::string& profilename, const std::string& certstr, const std::string& keystr, - const std::string& dhstr, unsigned int mindh, const std::string& hashstr, - const std::string& ciphersuitestr, const std::string& curvestr, - const std::string& castr, const std::string& crlstr, - unsigned int recsize, - CTRDRBG& ctrdrbg, - int minver, int maxver, - bool requestclientcert - ) - : name(profilename) - , x509cred(certstr, keystr) - , ciphersuites(ciphersuitestr) - , curves(curvestr) - , serverctx(ctrdrbg, MBEDTLS_SSL_IS_SERVER) - , clientctx(ctrdrbg, MBEDTLS_SSL_IS_CLIENT) - , cacerts(castr, true) - , crl(crlstr) - , hash(hashstr) - , outrecsize(recsize) + public: + struct Config + { + const std::string name; + + CTRDRBG& ctrdrbg; + + const std::string certstr; + const std::string keystr; + const std::string dhstr; + + const std::string ciphersuitestr; + const std::string curvestr; + const unsigned int mindh; + const std::string hashstr; + + std::string crlstr; + std::string castr; + + const int minver; + const int maxver; + const unsigned int outrecsize; + const bool requestclientcert; + + Config(const std::string& profilename, ConfigTag* tag, CTRDRBG& ctr_drbg) + : name(profilename) + , ctrdrbg(ctr_drbg) + , certstr(ReadFile(tag->getString("certfile", "cert.pem", 1))) + , keystr(ReadFile(tag->getString("keyfile", "key.pem", 1))) + , dhstr(ReadFile(tag->getString("dhfile", "dhparams.pem", 1))) + , ciphersuitestr(tag->getString("ciphersuites")) + , curvestr(tag->getString("curves")) + , mindh(tag->getUInt("mindhbits", 2048)) + , hashstr(tag->getString("hash", "sha256", 1)) + , castr(tag->getString("cafile")) + , minver(tag->getUInt("minver", 0)) + , maxver(tag->getUInt("maxver", 0)) + , outrecsize(tag->getUInt("outrecsize", 2048, 512, 16384)) + , requestclientcert(tag->getBool("requestclientcert", true)) + { + if (!castr.empty()) + { + castr = ReadFile(castr); + crlstr = tag->getString("crlfile"); + if (!crlstr.empty()) + crlstr = ReadFile(crlstr); + } + } + }; + + Profile(Config& config) + : name(config.name) + , x509cred(config.certstr, config.keystr) + , ciphersuites(config.ciphersuitestr) + , curves(config.curvestr) + , serverctx(config.ctrdrbg, MBEDTLS_SSL_IS_SERVER) + , clientctx(config.ctrdrbg, MBEDTLS_SSL_IS_CLIENT) + , cacerts(config.castr, true) + , crl(config.crlstr) + , hash(config.hashstr) + , outrecsize(config.outrecsize) { serverctx.SetX509CertAndKey(x509cred); clientctx.SetX509CertAndKey(x509cred); - clientctx.SetMinDHBits(mindh); + clientctx.SetMinDHBits(config.mindh); if (!ciphersuites.empty()) { @@ -414,19 +470,19 @@ namespace mbedTLS clientctx.SetCurves(curves); } - serverctx.SetVersion(minver, maxver); - clientctx.SetVersion(minver, maxver); + serverctx.SetVersion(config.minver, config.maxver); + clientctx.SetVersion(config.minver, config.maxver); - if (!dhstr.empty()) + if (!config.dhstr.empty()) { - dhparams.set(dhstr); + dhparams.set(config.dhstr); serverctx.SetDHParams(dhparams); } clientctx.SetOptionalVerifyCert(); clientctx.SetCA(cacerts, crl); // The default for servers is to not request a client certificate from the peer - if (requestclientcert) + if (config.requestclientcert) { serverctx.SetOptionalVerifyCert(); serverctx.SetCA(cacerts, crl); @@ -442,35 +498,6 @@ namespace mbedTLS return ret; } - public: - static reference Create(const std::string& profilename, ConfigTag* tag, CTRDRBG& ctr_drbg) - { - const std::string certstr = ReadFile(tag->getString("certfile", "cert.pem")); - const std::string keystr = ReadFile(tag->getString("keyfile", "key.pem")); - const std::string dhstr = ReadFile(tag->getString("dhfile", "dhparams.pem")); - - const std::string ciphersuitestr = tag->getString("ciphersuites"); - const std::string curvestr = tag->getString("curves"); - unsigned int mindh = tag->getInt("mindhbits", 2048); - std::string hashstr = tag->getString("hash", "sha256"); - - std::string crlstr; - std::string castr = tag->getString("cafile"); - if (!castr.empty()) - { - castr = ReadFile(castr); - crlstr = tag->getString("crlfile"); - if (!crlstr.empty()) - crlstr = ReadFile(crlstr); - } - - int minver = tag->getInt("minver"); - int maxver = tag->getInt("maxver"); - unsigned int outrecsize = tag->getInt("outrecsize", 2048, 512, 16384); - const bool requestclientcert = tag->getBool("requestclientcert", true); - return new Profile(profilename, certstr, keystr, dhstr, mindh, hashstr, ciphersuitestr, curvestr, castr, crlstr, outrecsize, ctr_drbg, minver, maxver, requestclientcert); - } - /** Set up the given session with the settings in this profile */ void SetupClientSession(mbedtls_ssl_context* sess) @@ -501,7 +528,6 @@ class mbedTLSIOHook : public SSLIOHook mbedtls_ssl_context sess; Status status; - reference profile; void CloseSession() { @@ -560,7 +586,7 @@ class mbedTLSIOHook : public SSLIOHook } CloseSession(); - sock->SetError("No SSL session"); + sock->SetError("No TLS (SSL) session"); return -1; } @@ -575,7 +601,7 @@ class mbedTLSIOHook : public SSLIOHook } // If there is a certificate we can always generate a fingerprint - certificate->fingerprint = profile->GetHash().hash(cert->raw.p, cert->raw.len); + certificate->fingerprint = GetProfile().GetHash().hash(cert->raw.p, cert->raw.len); // At this point mbedTLS verified the cert already, we just need to check the results const uint32_t flags = mbedtls_ssl_get_verify_result(&sess); @@ -649,16 +675,15 @@ class mbedTLSIOHook : public SSLIOHook } public: - mbedTLSIOHook(IOHookProvider* hookprov, StreamSocket* sock, bool isserver, mbedTLS::Profile* sslprofile) + mbedTLSIOHook(IOHookProvider* hookprov, StreamSocket* sock, bool isserver) : SSLIOHook(hookprov) , status(ISSL_NONE) - , profile(sslprofile) { mbedtls_ssl_init(&sess); if (isserver) - profile->SetupServerSession(&sess); + GetProfile().SetupServerSession(&sess); else - profile->SetupClientSession(&sess); + GetProfile().SetupClientSession(&sess); mbedtls_ssl_set_bio(&sess, reinterpret_cast(sock), Push, Pull, NULL); @@ -725,7 +750,7 @@ class mbedTLSIOHook : public SSLIOHook // Session is ready for transferring application data while (!sendq.empty()) { - FlattenSendQueue(sendq, profile->GetOutgoingRecordSize()); + FlattenSendQueue(sendq, GetProfile().GetOutgoingRecordSize()); const StreamSocket::SendQueue::Element& buffer = sendq.front(); int ret = mbedtls_ssl_write(&sess, reinterpret_cast(buffer.data()), buffer.length()); if (ret == (int)buffer.length()) @@ -782,17 +807,24 @@ class mbedTLSIOHook : public SSLIOHook out.append(ciphersuitestr + skip); } + bool GetServerName(std::string& out) const CXX11_OVERRIDE + { + // TODO: Implement SNI support. + return false; + } + + mbedTLS::Profile& GetProfile(); bool IsHandshakeDone() const { return (status == ISSL_HANDSHAKEN); } }; -class mbedTLSIOHookProvider : public refcountbase, public IOHookProvider +class mbedTLSIOHookProvider : public IOHookProvider { - reference profile; + mbedTLS::Profile profile; public: - mbedTLSIOHookProvider(Module* mod, mbedTLS::Profile* prof) - : IOHookProvider(mod, "ssl/" + prof->GetName(), IOHookProvider::IOH_SSL) - , profile(prof) + mbedTLSIOHookProvider(Module* mod, mbedTLS::Profile::Config& config) + : IOHookProvider(mod, "ssl/" + config.name, IOHookProvider::IOH_SSL) + , profile(config) { ServerInstance->Modules->AddService(*this); } @@ -804,15 +836,23 @@ class mbedTLSIOHookProvider : public refcountbase, public IOHookProvider void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { - new mbedTLSIOHook(this, sock, true, profile); + new mbedTLSIOHook(this, sock, true); } void OnConnect(StreamSocket* sock) CXX11_OVERRIDE { - new mbedTLSIOHook(this, sock, false, profile); + new mbedTLSIOHook(this, sock, false); } + + mbedTLS::Profile& GetProfile() { return profile; } }; +mbedTLS::Profile& mbedTLSIOHook::GetProfile() +{ + IOHookProvider* hookprov = prov; + return static_cast(hookprov)->GetProfile(); +} + class ModuleSSLmbedTLS : public Module { typedef std::vector > ProfileList; @@ -825,7 +865,7 @@ class ModuleSSLmbedTLS : public Module { // First, store all profiles in a new, temporary container. If no problems occur, swap the two // containers; this way if something goes wrong we can go back and continue using the current profiles, - // avoiding unpleasant situations where no new SSL connections are possible. + // avoiding unpleasant situations where no new TLS (SSL) connections are possible. ProfileList newprofiles; ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile"); @@ -838,43 +878,56 @@ class ModuleSSLmbedTLS : public Module try { - reference profile(mbedTLS::Profile::Create(defname, tag, ctr_drbg)); - newprofiles.push_back(new mbedTLSIOHookProvider(this, profile)); + mbedTLS::Profile::Config profileconfig(defname, tag, ctr_drbg); + newprofiles.push_back(new mbedTLSIOHookProvider(this, profileconfig)); } catch (CoreException& ex) { - throw ModuleException("Error while initializing the default SSL profile - " + ex.GetReason()); + throw ModuleException("Error while initializing the default TLS (SSL) profile - " + ex.GetReason()); } } - - for (ConfigIter i = tags.first; i != tags.second; ++i) + else { - ConfigTag* tag = i->second; - if (tag->getString("provider") != "mbedtls") - continue; - - std::string name = tag->getString("name"); - if (name.empty()) + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "You have defined an tag; you should use this in place of \"mbedtls\" when configuring TLS (SSL) connections in or "); + for (ConfigIter i = tags.first; i != tags.second; ++i) { - ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring tag without name at " + tag->getTagLocation()); - continue; - } + ConfigTag* tag = i->second; + if (!stdalgo::string::equalsci(tag->getString("provider"), "mbedtls")) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring non-mbedTLS tag at " + tag->getTagLocation()); + continue; + } - reference profile; - try - { - profile = mbedTLS::Profile::Create(name, tag, ctr_drbg); - } - catch (CoreException& ex) - { - throw ModuleException("Error while initializing SSL profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason()); - } + std::string name = tag->getString("name"); + if (name.empty()) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring tag without name at " + tag->getTagLocation()); + continue; + } - newprofiles.push_back(new mbedTLSIOHookProvider(this, profile)); + reference prov; + try + { + mbedTLS::Profile::Config profileconfig(name, tag, ctr_drbg); + prov = new mbedTLSIOHookProvider(this, profileconfig); + } + catch (CoreException& ex) + { + throw ModuleException("Error while initializing TLS (SSL) profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason()); + } + + newprofiles.push_back(prov); + } } // New profiles are ok, begin using them // Old profiles are deleted when their refcount drops to zero + for (ProfileList::iterator i = profiles.begin(); i != profiles.end(); ++i) + { + mbedTLSIOHookProvider& prov = **i; + ServerInstance->Modules.DelService(prov); + } + profiles.swap(newprofiles); } @@ -892,12 +945,13 @@ class ModuleSSLmbedTLS : public Module void OnModuleRehash(User* user, const std::string ¶m) CXX11_OVERRIDE { - if (param != "ssl") + if (!irc::equals(param, "tls") && !irc::equals(param, "ssl")) return; try { ReadProfiles(); + ServerInstance->SNO->WriteToSnoMask('a', "TLS (SSL) module mbedTLS rehashed."); } catch (ModuleException& ex) { @@ -913,9 +967,9 @@ class ModuleSSLmbedTLS : public Module LocalUser* user = IS_LOCAL(static_cast(item)); if ((user) && (user->eh.GetModHook(this))) { - // User is using SSL, they're a local user, and they're using our IOHook. - // Potentially there could be multiple SSL modules loaded at once on different ports. - ServerInstance->Users.QuitUser(user, "SSL module unloading"); + // User is using TLS (SSL), they're a local user, and they're using our IOHook. + // Potentially there could be multiple TLS (SSL) modules loaded at once on different ports. + ServerInstance->Users.QuitUser(user, "mbedTLS module unloading"); } } @@ -929,7 +983,7 @@ class ModuleSSLmbedTLS : public Module Version GetVersion() CXX11_OVERRIDE { - return Version("Provides SSL support via mbedTLS (PolarSSL)", VF_VENDOR); + return Version("Allows TLS (SSL) encrypted connections using the mbedTLS library.", VF_VENDOR); } };