2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2019 Matt Schatz <genius3000@g3k.solutions>
5 * Copyright (C) 2016-2020 Sadie Powell <sadie@witchery.services>
6 * Copyright (C) 2016-2017 Attila Molnar <attilamolnar@hush.com>
8 * This file is part of InspIRCd. InspIRCd is free software: you can
9 * redistribute it and/or modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation, version 2.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /// $LinkerFlags: -lmbedtls
23 /// $PackageInfo: require_system("arch") mbedtls
24 /// $PackageInfo: require_system("darwin") mbedtls
25 /// $PackageInfo: require_system("debian" "9.0") libmbedtls-dev
26 /// $PackageInfo: require_system("ubuntu" "16.04") libmbedtls-dev
30 #include "modules/ssl.h"
32 // Fix warnings about the use of commas at end of enumerator lists on C++03.
34 # pragma clang diagnostic ignored "-Wc++11-extensions"
35 #elif defined __GNUC__
36 # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8))
37 # pragma GCC diagnostic ignored "-Wpedantic"
39 # pragma GCC diagnostic ignored "-pedantic"
43 #include <mbedtls/ctr_drbg.h>
44 #include <mbedtls/dhm.h>
45 #include <mbedtls/ecp.h>
46 #include <mbedtls/entropy.h>
47 #include <mbedtls/error.h>
48 #include <mbedtls/md.h>
49 #include <mbedtls/pk.h>
50 #include <mbedtls/ssl.h>
51 #include <mbedtls/ssl_ciphersuites.h>
52 #include <mbedtls/version.h>
53 #include <mbedtls/x509.h>
54 #include <mbedtls/x509_crt.h>
55 #include <mbedtls/x509_crl.h>
57 #ifdef INSPIRCD_MBEDTLS_LIBRARY_DEBUG
58 #include <mbedtls/debug.h>
63 class Exception : public ModuleException
66 Exception(const std::string& reason)
67 : ModuleException(reason) { }
70 std::string ErrorToString(int errcode)
73 mbedtls_strerror(errcode, buf, sizeof(buf));
77 void ThrowOnError(int errcode, const char* msg)
81 std::string reason = msg;
82 reason.append(" :").append(ErrorToString(errcode));
83 throw Exception(reason);
87 template <typename T, void (*init)(T*), void (*deinit)(T*)>
103 T* get() { return &obj; }
104 const T* get() const { return &obj; }
107 typedef RAIIObj<mbedtls_entropy_context, mbedtls_entropy_init, mbedtls_entropy_free> Entropy;
109 class CTRDRBG : private RAIIObj<mbedtls_ctr_drbg_context, mbedtls_ctr_drbg_init, mbedtls_ctr_drbg_free>
112 bool Seed(Entropy& entropy)
114 return (mbedtls_ctr_drbg_seed(get(), mbedtls_entropy_func, entropy.get(), NULL, 0) == 0);
117 void SetupConf(mbedtls_ssl_config* conf)
119 mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, get());
123 class DHParams : public RAIIObj<mbedtls_dhm_context, mbedtls_dhm_init, mbedtls_dhm_free>
126 void set(const std::string& dhstr)
128 // Last parameter is buffer size, must include the terminating null
129 int ret = mbedtls_dhm_parse_dhm(get(), reinterpret_cast<const unsigned char*>(dhstr.c_str()), dhstr.size()+1);
130 ThrowOnError(ret, "Unable to import DH params");
134 class X509Key : public RAIIObj<mbedtls_pk_context, mbedtls_pk_init, mbedtls_pk_free>
138 X509Key(const std::string& keystr)
140 int ret = mbedtls_pk_parse_key(get(), reinterpret_cast<const unsigned char*>(keystr.c_str()), keystr.size()+1, NULL, 0);
141 ThrowOnError(ret, "Unable to import private key");
147 std::vector<int> list;
150 Ciphersuites(const std::string& str)
152 // mbedTLS uses the ciphersuite format "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256" internally.
153 // This is a bit verbose, so we make life a bit simpler for admins by not requiring them to supply the static parts.
154 irc::sepstream ss(str, ':');
155 for (std::string token; ss.GetToken(token); )
157 // Prepend "TLS-" if not there
158 if (token.compare(0, 4, "TLS-", 4))
159 token.insert(0, "TLS-");
161 const int id = mbedtls_ssl_get_ciphersuite_id(token.c_str());
163 throw Exception("Unknown ciphersuite " + token);
169 const int* get() const { return &list.front(); }
170 bool empty() const { return (list.size() <= 1); }
175 std::vector<mbedtls_ecp_group_id> list;
178 Curves(const std::string& str)
180 irc::sepstream ss(str, ':');
181 for (std::string token; ss.GetToken(token); )
183 const mbedtls_ecp_curve_info* curve = mbedtls_ecp_curve_info_from_name(token.c_str());
185 throw Exception("Unknown curve " + token);
186 list.push_back(curve->grp_id);
188 list.push_back(MBEDTLS_ECP_DP_NONE);
191 const mbedtls_ecp_group_id* get() const { return &list.front(); }
192 bool empty() const { return (list.size() <= 1); }
195 class X509CertList : public RAIIObj<mbedtls_x509_crt, mbedtls_x509_crt_init, mbedtls_x509_crt_free>
198 /** Import or create empty */
199 X509CertList(const std::string& certstr, bool allowempty = false)
201 if ((allowempty) && (certstr.empty()))
203 int ret = mbedtls_x509_crt_parse(get(), reinterpret_cast<const unsigned char*>(certstr.c_str()), certstr.size()+1);
204 ThrowOnError(ret, "Unable to load certificates");
207 bool empty() const { return (get()->raw.p != NULL); }
210 class X509CRL : public RAIIObj<mbedtls_x509_crl, mbedtls_x509_crl_init, mbedtls_x509_crl_free>
213 X509CRL(const std::string& crlstr)
217 int ret = mbedtls_x509_crl_parse(get(), reinterpret_cast<const unsigned char*>(crlstr.c_str()), crlstr.size()+1);
218 ThrowOnError(ret, "Unable to load CRL");
222 class X509Credentials
228 /** Certificate list, presented to the peer
233 X509Credentials(const std::string& certstr, const std::string& keystr)
237 // Verify that one of the certs match the private key
239 for (mbedtls_x509_crt* cert = certs.get(); cert; cert = cert->next)
241 if (mbedtls_pk_check_pair(&cert->pk, key.get()) == 0)
248 throw Exception("Public/private key pair does not match");
251 mbedtls_pk_context* getkey() { return key.get(); }
252 mbedtls_x509_crt* getcerts() { return certs.get(); }
257 mbedtls_ssl_config conf;
259 #ifdef INSPIRCD_MBEDTLS_LIBRARY_DEBUG
260 static void DebugLogFunc(void* userptr, int level, const char* file, int line, const char* msg)
262 // Remove trailing \n
263 size_t len = strlen(msg);
264 if ((len > 0) && (msg[len-1] == '\n'))
266 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s:%d %.*s", file, line, len, msg);
271 Context(CTRDRBG& ctrdrbg, unsigned int endpoint)
273 mbedtls_ssl_config_init(&conf);
274 #ifdef INSPIRCD_MBEDTLS_LIBRARY_DEBUG
275 mbedtls_debug_set_threshold(INT_MAX);
276 mbedtls_ssl_conf_dbg(&conf, DebugLogFunc, NULL);
279 // TODO: check ret of mbedtls_ssl_config_defaults
280 mbedtls_ssl_config_defaults(&conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
281 ctrdrbg.SetupConf(&conf);
286 mbedtls_ssl_config_free(&conf);
289 void SetMinDHBits(unsigned int mindh)
291 mbedtls_ssl_conf_dhm_min_bitlen(&conf, mindh);
294 void SetDHParams(DHParams& dh)
296 mbedtls_ssl_conf_dh_param_ctx(&conf, dh.get());
299 void SetX509CertAndKey(X509Credentials& x509cred)
301 mbedtls_ssl_conf_own_cert(&conf, x509cred.getcerts(), x509cred.getkey());
304 void SetCiphersuites(const Ciphersuites& ciphersuites)
306 mbedtls_ssl_conf_ciphersuites(&conf, ciphersuites.get());
309 void SetCurves(const Curves& curves)
311 mbedtls_ssl_conf_curves(&conf, curves.get());
314 void SetVersion(int minver, int maxver)
316 // SSL v3 support cannot be enabled
318 mbedtls_ssl_conf_min_version(&conf, MBEDTLS_SSL_MAJOR_VERSION_3, minver);
320 mbedtls_ssl_conf_max_version(&conf, MBEDTLS_SSL_MAJOR_VERSION_3, maxver);
323 void SetCA(X509CertList& certs, X509CRL& crl)
325 mbedtls_ssl_conf_ca_chain(&conf, certs.get(), crl.get());
328 void SetOptionalVerifyCert()
330 mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
333 const mbedtls_ssl_config* GetConf() const { return &conf; }
338 const mbedtls_md_info_t* md;
340 /** Buffer where cert hashes are written temporarily
342 mutable std::vector<unsigned char> buf;
345 Hash(std::string hashstr)
347 std::transform(hashstr.begin(), hashstr.end(), hashstr.begin(), ::toupper);
348 md = mbedtls_md_info_from_string(hashstr.c_str());
350 throw Exception("Unknown hash: " + hashstr);
352 buf.resize(mbedtls_md_get_size(md));
355 std::string hash(const unsigned char* input, size_t length) const
357 mbedtls_md(md, input, length, &buf.front());
358 return BinToHex(&buf.front(), buf.size());
364 /** Name of this profile
366 const std::string name;
368 X509Credentials x509cred;
370 /** Ciphersuites to use
372 Ciphersuites ciphersuites;
374 /** Curves accepted for use in ECDHE and in the peer's end-entity certificate
383 X509CertList cacerts;
387 /** Hashing algorithm to use when generating certificate fingerprints
391 /** Rough max size of records to send
393 const unsigned int outrecsize;
398 const std::string name;
402 const std::string certstr;
403 const std::string keystr;
404 const std::string dhstr;
406 const std::string ciphersuitestr;
407 const std::string curvestr;
408 const unsigned int mindh;
409 const std::string hashstr;
416 const unsigned int outrecsize;
417 const bool requestclientcert;
419 Config(const std::string& profilename, ConfigTag* tag, CTRDRBG& ctr_drbg)
422 , certstr(ReadFile(tag->getString("certfile", "cert.pem", 1)))
423 , keystr(ReadFile(tag->getString("keyfile", "key.pem", 1)))
424 , dhstr(ReadFile(tag->getString("dhfile", "dhparams.pem", 1)))
425 , ciphersuitestr(tag->getString("ciphersuites"))
426 , curvestr(tag->getString("curves"))
427 , mindh(tag->getUInt("mindhbits", 2048))
428 , hashstr(tag->getString("hash", "sha256", 1))
429 , castr(tag->getString("cafile"))
430 , minver(tag->getUInt("minver", 0))
431 , maxver(tag->getUInt("maxver", 0))
432 , outrecsize(tag->getUInt("outrecsize", 2048, 512, 16384))
433 , requestclientcert(tag->getBool("requestclientcert", true))
437 castr = ReadFile(castr);
438 crlstr = tag->getString("crlfile");
440 crlstr = ReadFile(crlstr);
445 Profile(Config& config)
447 , x509cred(config.certstr, config.keystr)
448 , ciphersuites(config.ciphersuitestr)
449 , curves(config.curvestr)
450 , serverctx(config.ctrdrbg, MBEDTLS_SSL_IS_SERVER)
451 , clientctx(config.ctrdrbg, MBEDTLS_SSL_IS_CLIENT)
452 , cacerts(config.castr, true)
454 , hash(config.hashstr)
455 , outrecsize(config.outrecsize)
457 serverctx.SetX509CertAndKey(x509cred);
458 clientctx.SetX509CertAndKey(x509cred);
459 clientctx.SetMinDHBits(config.mindh);
461 if (!ciphersuites.empty())
463 serverctx.SetCiphersuites(ciphersuites);
464 clientctx.SetCiphersuites(ciphersuites);
469 serverctx.SetCurves(curves);
470 clientctx.SetCurves(curves);
473 serverctx.SetVersion(config.minver, config.maxver);
474 clientctx.SetVersion(config.minver, config.maxver);
476 if (!config.dhstr.empty())
478 dhparams.set(config.dhstr);
479 serverctx.SetDHParams(dhparams);
482 clientctx.SetOptionalVerifyCert();
483 clientctx.SetCA(cacerts, crl);
484 // The default for servers is to not request a client certificate from the peer
485 if (config.requestclientcert)
487 serverctx.SetOptionalVerifyCert();
488 serverctx.SetCA(cacerts, crl);
492 static std::string ReadFile(const std::string& filename)
494 FileReader reader(filename);
495 std::string ret = reader.GetString();
497 throw Exception("Cannot read file " + filename);
501 /** Set up the given session with the settings in this profile
503 void SetupClientSession(mbedtls_ssl_context* sess)
505 mbedtls_ssl_setup(sess, clientctx.GetConf());
508 void SetupServerSession(mbedtls_ssl_context* sess)
510 mbedtls_ssl_setup(sess, serverctx.GetConf());
513 const std::string& GetName() const { return name; }
514 X509Credentials& GetX509Credentials() { return x509cred; }
515 unsigned int GetOutgoingRecordSize() const { return outrecsize; }
516 const Hash& GetHash() const { return hash; }
520 class mbedTLSIOHook : public SSLIOHook
529 mbedtls_ssl_context sess;
534 if (status == ISSL_NONE)
537 mbedtls_ssl_close_notify(&sess);
538 mbedtls_ssl_free(&sess);
543 // Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed
544 int Handshake(StreamSocket* sock)
546 int ret = mbedtls_ssl_handshake(&sess);
549 // Change the seesion state
550 this->status = ISSL_HANDSHAKEN;
554 // Finish writing, if any left
555 SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
560 this->status = ISSL_HANDSHAKING;
561 if (ret == MBEDTLS_ERR_SSL_WANT_READ)
563 SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
566 else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE)
568 SocketEngine::ChangeEventMask(sock, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
572 sock->SetError("Handshake Failed - " + mbedTLS::ErrorToString(ret));
577 // Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error
578 int PrepareIO(StreamSocket* sock)
580 if (status == ISSL_HANDSHAKEN)
582 else if (status == ISSL_HANDSHAKING)
584 // The handshake isn't finished, try to finish it
585 return Handshake(sock);
589 sock->SetError("No TLS (SSL) session");
593 void VerifyCertificate()
595 this->certificate = new ssl_cert;
596 const mbedtls_x509_crt* const cert = mbedtls_ssl_get_peer_cert(&sess);
599 certificate->error = "No client certificate sent";
603 // If there is a certificate we can always generate a fingerprint
604 certificate->fingerprint = GetProfile().GetHash().hash(cert->raw.p, cert->raw.len);
606 // At this point mbedTLS verified the cert already, we just need to check the results
607 const uint32_t flags = mbedtls_ssl_get_verify_result(&sess);
608 if (flags == 0xFFFFFFFF)
610 certificate->error = "Internal error during verification";
616 // Verification succeeded
617 certificate->trusted = true;
621 // Verification failed
622 certificate->trusted = false;
623 if ((flags & MBEDTLS_X509_BADCERT_EXPIRED) || (flags & MBEDTLS_X509_BADCERT_FUTURE))
624 certificate->error = "Not activated, or expired certificate";
627 certificate->unknownsigner = (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED);
628 certificate->revoked = (flags & MBEDTLS_X509_BADCERT_REVOKED);
629 certificate->invalid = ((flags & MBEDTLS_X509_BADCERT_BAD_KEY) || (flags & MBEDTLS_X509_BADCERT_BAD_MD) || (flags & MBEDTLS_X509_BADCERT_BAD_PK));
631 GetDNString(&cert->subject, certificate->dn);
632 GetDNString(&cert->issuer, certificate->issuer);
635 static void GetDNString(const mbedtls_x509_name* x509name, std::string& out)
638 const int ret = mbedtls_x509_dn_gets(buf, sizeof(buf), x509name);
642 out.assign(buf, ret);
645 static int Pull(void* userptr, unsigned char* buffer, size_t size)
647 StreamSocket* const sock = reinterpret_cast<StreamSocket*>(userptr);
648 if (sock->GetEventMask() & FD_READ_WILL_BLOCK)
649 return MBEDTLS_ERR_SSL_WANT_READ;
651 const int ret = SocketEngine::Recv(sock, reinterpret_cast<char*>(buffer), size, 0);
654 SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK);
655 if ((ret == -1) && (SocketEngine::IgnoreError()))
656 return MBEDTLS_ERR_SSL_WANT_READ;
661 static int Push(void* userptr, const unsigned char* buffer, size_t size)
663 StreamSocket* const sock = reinterpret_cast<StreamSocket*>(userptr);
664 if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK)
665 return MBEDTLS_ERR_SSL_WANT_WRITE;
667 const int ret = SocketEngine::Send(sock, buffer, size, 0);
670 SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK);
671 if ((ret == -1) && (SocketEngine::IgnoreError()))
672 return MBEDTLS_ERR_SSL_WANT_WRITE;
678 mbedTLSIOHook(IOHookProvider* hookprov, StreamSocket* sock, bool isserver)
679 : SSLIOHook(hookprov)
682 mbedtls_ssl_init(&sess);
684 GetProfile().SetupServerSession(&sess);
686 GetProfile().SetupClientSession(&sess);
688 mbedtls_ssl_set_bio(&sess, reinterpret_cast<void*>(sock), Push, Pull, NULL);
690 sock->AddIOHook(this);
694 void OnStreamSocketClose(StreamSocket* sock) CXX11_OVERRIDE
699 int OnStreamSocketRead(StreamSocket* sock, std::string& recvq) CXX11_OVERRIDE
701 // Finish handshake if needed
702 int prepret = PrepareIO(sock);
706 // If we resumed the handshake then this->status will be ISSL_HANDSHAKEN.
707 char* const readbuf = ServerInstance->GetReadBuffer();
708 const size_t readbufsize = ServerInstance->Config->NetBufferSize;
709 int ret = mbedtls_ssl_read(&sess, reinterpret_cast<unsigned char*>(readbuf), readbufsize);
712 recvq.append(readbuf, ret);
714 // Schedule a read if there is still data in the mbedTLS buffer
715 if (mbedtls_ssl_get_bytes_avail(&sess) > 0)
716 SocketEngine::ChangeEventMask(sock, FD_ADD_TRIAL_READ);
719 else if (ret == MBEDTLS_ERR_SSL_WANT_READ)
721 SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ);
724 else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE)
726 SocketEngine::ChangeEventMask(sock, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
731 sock->SetError("Connection closed");
735 else // error or MBEDTLS_ERR_SSL_CLIENT_RECONNECT which we treat as an error
737 sock->SetError(mbedTLS::ErrorToString(ret));
743 int OnStreamSocketWrite(StreamSocket* sock, StreamSocket::SendQueue& sendq) CXX11_OVERRIDE
745 // Finish handshake if needed
746 int prepret = PrepareIO(sock);
750 // Session is ready for transferring application data
751 while (!sendq.empty())
753 FlattenSendQueue(sendq, GetProfile().GetOutgoingRecordSize());
754 const StreamSocket::SendQueue::Element& buffer = sendq.front();
755 int ret = mbedtls_ssl_write(&sess, reinterpret_cast<const unsigned char*>(buffer.data()), buffer.length());
756 if (ret == (int)buffer.length())
758 // Wrote entire record, continue sending
763 sendq.erase_front(ret);
764 SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE);
769 sock->SetError("Connection closed");
773 else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE)
775 SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE);
778 else if (ret == MBEDTLS_ERR_SSL_WANT_READ)
780 SocketEngine::ChangeEventMask(sock, FD_WANT_POLL_READ);
785 sock->SetError(mbedTLS::ErrorToString(ret));
791 SocketEngine::ChangeEventMask(sock, FD_WANT_NO_WRITE);
795 void GetCiphersuite(std::string& out) const CXX11_OVERRIDE
797 if (!IsHandshakeDone())
799 out.append(mbedtls_ssl_get_version(&sess)).push_back('-');
801 // All mbedTLS ciphersuite names currently begin with "TLS-" which provides no useful information so skip it, but be prepared if it changes
802 const char* const ciphersuitestr = mbedtls_ssl_get_ciphersuite(&sess);
803 const char prefix[] = "TLS-";
804 unsigned int skip = sizeof(prefix)-1;
805 if (strncmp(ciphersuitestr, prefix, sizeof(prefix)-1))
807 out.append(ciphersuitestr + skip);
810 bool GetServerName(std::string& out) const CXX11_OVERRIDE
812 // TODO: Implement SNI support.
816 mbedTLS::Profile& GetProfile();
817 bool IsHandshakeDone() const { return (status == ISSL_HANDSHAKEN); }
820 class mbedTLSIOHookProvider : public IOHookProvider
822 mbedTLS::Profile profile;
825 mbedTLSIOHookProvider(Module* mod, mbedTLS::Profile::Config& config)
826 : IOHookProvider(mod, "ssl/" + config.name, IOHookProvider::IOH_SSL)
829 ServerInstance->Modules->AddService(*this);
832 ~mbedTLSIOHookProvider()
834 ServerInstance->Modules->DelService(*this);
837 void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
839 new mbedTLSIOHook(this, sock, true);
842 void OnConnect(StreamSocket* sock) CXX11_OVERRIDE
844 new mbedTLSIOHook(this, sock, false);
847 mbedTLS::Profile& GetProfile() { return profile; }
850 mbedTLS::Profile& mbedTLSIOHook::GetProfile()
852 IOHookProvider* hookprov = prov;
853 return static_cast<mbedTLSIOHookProvider*>(hookprov)->GetProfile();
856 class ModuleSSLmbedTLS : public Module
858 typedef std::vector<reference<mbedTLSIOHookProvider> > ProfileList;
860 mbedTLS::Entropy entropy;
861 mbedTLS::CTRDRBG ctr_drbg;
862 ProfileList profiles;
866 // First, store all profiles in a new, temporary container. If no problems occur, swap the two
867 // containers; this way if something goes wrong we can go back and continue using the current profiles,
868 // avoiding unpleasant situations where no new TLS (SSL) connections are possible.
869 ProfileList newprofiles;
871 ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile");
872 if (tags.first == tags.second)
874 // No <sslprofile> tags found, create a profile named "mbedtls" from settings in the <mbedtls> block
875 const std::string defname = "mbedtls";
876 ConfigTag* tag = ServerInstance->Config->ConfValue(defname);
877 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No <sslprofile> tags found; using settings from the <mbedtls> tag");
881 mbedTLS::Profile::Config profileconfig(defname, tag, ctr_drbg);
882 newprofiles.push_back(new mbedTLSIOHookProvider(this, profileconfig));
884 catch (CoreException& ex)
886 throw ModuleException("Error while initializing the default TLS (SSL) profile - " + ex.GetReason());
891 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "You have defined an <sslprofile> tag; you should use this in place of \"mbedtls\" when configuring TLS (SSL) connections in <bind:ssl> or <link:ssl>");
892 for (ConfigIter i = tags.first; i != tags.second; ++i)
894 ConfigTag* tag = i->second;
895 if (!stdalgo::string::equalsci(tag->getString("provider"), "mbedtls"))
898 std::string name = tag->getString("name");
901 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring <sslprofile> tag without name at " + tag->getTagLocation());
905 reference<mbedTLSIOHookProvider> prov;
908 mbedTLS::Profile::Config profileconfig(name, tag, ctr_drbg);
909 prov = new mbedTLSIOHookProvider(this, profileconfig);
911 catch (CoreException& ex)
913 throw ModuleException("Error while initializing TLS (SSL) profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason());
916 newprofiles.push_back(prov);
920 // New profiles are ok, begin using them
921 // Old profiles are deleted when their refcount drops to zero
922 for (ProfileList::iterator i = profiles.begin(); i != profiles.end(); ++i)
924 mbedTLSIOHookProvider& prov = **i;
925 ServerInstance->Modules.DelService(prov);
928 profiles.swap(newprofiles);
932 void init() CXX11_OVERRIDE
934 char verbuf[16]; // Should be at least 9 bytes in size
935 mbedtls_version_get_string(verbuf);
936 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "mbedTLS lib version %s module was compiled for " MBEDTLS_VERSION_STRING, verbuf);
938 if (!ctr_drbg.Seed(entropy))
939 throw ModuleException("CTR DRBG seed failed");
943 void OnModuleRehash(User* user, const std::string ¶m) CXX11_OVERRIDE
945 if (!irc::equals(param, "tls") && !irc::equals(param, "ssl"))
951 ServerInstance->SNO->WriteToSnoMask('a', "TLS (SSL) module mbedTLS rehashed.");
953 catch (ModuleException& ex)
955 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings.");
959 void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE
961 if (type != ExtensionItem::EXT_USER)
964 LocalUser* user = IS_LOCAL(static_cast<User*>(item));
965 if ((user) && (user->eh.GetModHook(this)))
967 // User is using TLS (SSL), they're a local user, and they're using our IOHook.
968 // Potentially there could be multiple TLS (SSL) modules loaded at once on different ports.
969 ServerInstance->Users.QuitUser(user, "mbedTLS module unloading");
973 ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE
975 const mbedTLSIOHook* const iohook = static_cast<mbedTLSIOHook*>(user->eh.GetModHook(this));
976 if ((iohook) && (!iohook->IsHandshakeDone()))
978 return MOD_RES_PASSTHRU;
981 Version GetVersion() CXX11_OVERRIDE
983 return Version("Allows TLS (SSL) encrypted connections using the mbedTLS library.", VF_VENDOR);
987 MODULE_INIT(ModuleSSLmbedTLS)