]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_ssl_openssl.cpp
40861b1f81b2bb48e48153c50a1ae616379deccc
[user/henk/code/inspircd.git] / src / modules / extra / m_ssl_openssl.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
6  *   Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc>
7  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
8  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
9  *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
10  *
11  * This file is part of InspIRCd.  InspIRCd is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation, version 2.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 /// $CompilerFlags: find_compiler_flags("openssl")
25 /// $LinkerFlags: find_linker_flags("openssl" "-lssl -lcrypto")
26
27 /// $PackageInfo: require_system("centos") openssl-devel pkgconfig
28 /// $PackageInfo: require_system("darwin") openssl pkg-config
29 /// $PackageInfo: require_system("debian") libssl-dev openssl pkg-config
30 /// $PackageInfo: require_system("ubuntu") libssl-dev openssl pkg-config
31
32
33 #include "inspircd.h"
34 #include "iohook.h"
35 #include "modules/ssl.h"
36
37 // Ignore OpenSSL deprecation warnings on OS X Lion and newer.
38 #if defined __APPLE__
39 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
40 #endif
41
42 // Fix warnings about the use of `long long` on C++03.
43 #if defined __clang__
44 # pragma clang diagnostic ignored "-Wc++11-long-long"
45 #elif defined __GNUC__
46 # pragma GCC diagnostic ignored "-Wlong-long"
47 #endif
48
49 #include <openssl/ssl.h>
50 #include <openssl/err.h>
51
52 #ifdef _WIN32
53 # pragma comment(lib, "ssleay32.lib")
54 # pragma comment(lib, "libeay32.lib")
55 #endif
56
57 // BIO is opaque in OpenSSL 1.1 but the access API does not exist in 1.0 and older.
58 #if ((defined LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x10100000L))
59 # define BIO_get_data(BIO) BIO->ptr
60 # define BIO_set_data(BIO, VALUE) BIO->ptr = VALUE;
61 # define BIO_set_init(BIO, VALUE) BIO->init = VALUE;
62 #else
63 # define INSPIRCD_OPENSSL_OPAQUE_BIO
64 #endif
65
66 enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
67
68 static bool SelfSigned = false;
69 static int exdataindex;
70
71 char* get_error()
72 {
73         return ERR_error_string(ERR_get_error(), NULL);
74 }
75
76 static int OnVerify(int preverify_ok, X509_STORE_CTX* ctx);
77 static void StaticSSLInfoCallback(const SSL* ssl, int where, int rc);
78
79 namespace OpenSSL
80 {
81         class Exception : public ModuleException
82         {
83          public:
84                 Exception(const std::string& reason)
85                         : ModuleException(reason) { }
86         };
87
88         class DHParams
89         {
90                 DH* dh;
91
92          public:
93                 DHParams(const std::string& filename)
94                 {
95                         BIO* dhpfile = BIO_new_file(filename.c_str(), "r");
96                         if (dhpfile == NULL)
97                                 throw Exception("Couldn't open DH file " + filename);
98
99                         dh = PEM_read_bio_DHparams(dhpfile, NULL, NULL, NULL);
100                         BIO_free(dhpfile);
101
102                         if (!dh)
103                                 throw Exception("Couldn't read DH params from file " + filename);
104                 }
105
106                 ~DHParams()
107                 {
108                         DH_free(dh);
109                 }
110
111                 DH* get()
112                 {
113                         return dh;
114                 }
115         };
116
117         class Context
118         {
119                 SSL_CTX* const ctx;
120                 long ctx_options;
121
122          public:
123                 Context(SSL_CTX* context)
124                         : ctx(context)
125                 {
126                         // Sane default options for OpenSSL see https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
127                         // and when choosing a cipher, use the server's preferences instead of the client preferences.
128                         long opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE;
129                         // Only turn options on if they exist
130 #ifdef SSL_OP_SINGLE_ECDH_USE
131                         opts |= SSL_OP_SINGLE_ECDH_USE;
132 #endif
133 #ifdef SSL_OP_NO_TICKET
134                         opts |= SSL_OP_NO_TICKET;
135 #endif
136
137                         ctx_options = SSL_CTX_set_options(ctx, opts);
138
139                         long mode = SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
140 #ifdef SSL_MODE_RELEASE_BUFFERS
141                         mode |= SSL_MODE_RELEASE_BUFFERS;
142 #endif
143                         SSL_CTX_set_mode(ctx, mode);
144                         SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
145                         SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
146                         SSL_CTX_set_info_callback(ctx, StaticSSLInfoCallback);
147                 }
148
149                 ~Context()
150                 {
151                         SSL_CTX_free(ctx);
152                 }
153
154                 bool SetDH(DHParams& dh)
155                 {
156                         ERR_clear_error();
157                         return (SSL_CTX_set_tmp_dh(ctx, dh.get()) >= 0);
158                 }
159
160 #ifndef OPENSSL_NO_ECDH
161                 void SetECDH(const std::string& curvename)
162                 {
163                         int nid = OBJ_sn2nid(curvename.c_str());
164                         if (nid == 0)
165                                 throw Exception("Unknown curve: " + curvename);
166
167                         EC_KEY* eckey = EC_KEY_new_by_curve_name(nid);
168                         if (!eckey)
169                                 throw Exception("Unable to create EC key object");
170
171                         ERR_clear_error();
172                         bool ret = (SSL_CTX_set_tmp_ecdh(ctx, eckey) >= 0);
173                         EC_KEY_free(eckey);
174                         if (!ret)
175                                 throw Exception("Couldn't set ECDH parameters");
176                 }
177 #endif
178
179                 bool SetCiphers(const std::string& ciphers)
180                 {
181                         ERR_clear_error();
182                         return SSL_CTX_set_cipher_list(ctx, ciphers.c_str());
183                 }
184
185                 bool SetCerts(const std::string& filename)
186                 {
187                         ERR_clear_error();
188                         return SSL_CTX_use_certificate_chain_file(ctx, filename.c_str());
189                 }
190
191                 bool SetPrivateKey(const std::string& filename)
192                 {
193                         ERR_clear_error();
194                         return SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
195                 }
196
197                 bool SetCA(const std::string& filename)
198                 {
199                         ERR_clear_error();
200                         return SSL_CTX_load_verify_locations(ctx, filename.c_str(), 0);
201                 }
202
203                 void SetCRL(const std::string& crlfile, const std::string& crlpath, const std::string& crlmode)
204                 {
205                         if (crlfile.empty() && crlpath.empty())
206                                 return;
207
208                         /* Set CRL mode */
209                         unsigned long crlflags = X509_V_FLAG_CRL_CHECK;
210                         if (crlmode == "chain")
211                         {
212                                 crlflags |= X509_V_FLAG_CRL_CHECK_ALL;
213                         }
214                         else if (crlmode != "leaf")
215                         {
216                                 throw ModuleException("Unknown mode '" + crlmode + "'; expected either 'chain' (default) or 'leaf'");
217                         }
218
219                         /* Load CRL files */
220                         X509_STORE* store = SSL_CTX_get_cert_store(ctx);
221                         if (!store)
222                         {
223                                 throw ModuleException("Unable to get X509_STORE from SSL context; this should never happen");
224                         }
225                         ERR_clear_error();
226                         if (!X509_STORE_load_locations(store,
227                                 crlfile.empty() ? NULL : crlfile.c_str(),
228                                 crlpath.empty() ? NULL : crlpath.c_str()))
229                         {
230                                 int err = ERR_get_error();
231                                 throw ModuleException("Unable to load CRL file '" + crlfile + "' or CRL path '" + crlpath + "': '" + (err ? ERR_error_string(err, NULL) : "unknown") + "'");
232                         }
233
234                         /* Set CRL mode */
235                         if (X509_STORE_set_flags(store, crlflags) != 1)
236                         {
237                                 throw ModuleException("Unable to set X509 CRL flags");
238                         }
239                 }
240
241
242                 long GetDefaultContextOptions() const
243                 {
244                         return ctx_options;
245                 }
246
247                 long SetRawContextOptions(long setoptions, long clearoptions)
248                 {
249                         // Clear everything
250                         SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx));
251
252                         // Set the default options and what is in the conf
253                         SSL_CTX_set_options(ctx, ctx_options | setoptions);
254                         return SSL_CTX_clear_options(ctx, clearoptions);
255                 }
256
257                 void SetVerifyCert()
258                 {
259                         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
260                 }
261
262                 SSL* CreateServerSession()
263                 {
264                         SSL* sess = SSL_new(ctx);
265                         SSL_set_accept_state(sess); // Act as server
266                         return sess;
267                 }
268
269                 SSL* CreateClientSession()
270                 {
271                         SSL* sess = SSL_new(ctx);
272                         SSL_set_connect_state(sess); // Act as client
273                         return sess;
274                 }
275         };
276
277         class Profile
278         {
279                 /** Name of this profile
280                  */
281                 const std::string name;
282
283                 /** DH parameters in use
284                  */
285                 DHParams dh;
286
287                 /** OpenSSL makes us have two contexts, one for servers and one for clients
288                  */
289                 Context ctx;
290                 Context clictx;
291
292                 /** Digest to use when generating fingerprints
293                  */
294                 const EVP_MD* digest;
295
296                 /** Last error, set by error_callback()
297                  */
298                 std::string lasterr;
299
300                 /** True if renegotiations are allowed, false if not
301                  */
302                 const bool allowrenego;
303
304                 /** Rough max size of records to send
305                  */
306                 const unsigned int outrecsize;
307
308                 static int error_callback(const char* str, size_t len, void* u)
309                 {
310                         Profile* profile = reinterpret_cast<Profile*>(u);
311                         profile->lasterr = std::string(str, len - 1);
312                         return 0;
313                 }
314
315                 /** Set raw OpenSSL context (SSL_CTX) options from a config tag
316                  * @param ctxname Name of the context, client or server
317                  * @param tag Config tag defining this profile
318                  * @param context Context object to manipulate
319                  */
320                 void SetContextOptions(const std::string& ctxname, ConfigTag* tag, Context& context)
321                 {
322                         long setoptions = tag->getInt(ctxname + "setoptions");
323                         long clearoptions = tag->getInt(ctxname + "clearoptions");
324 #ifdef SSL_OP_NO_COMPRESSION
325                         if (!tag->getBool("compression", false)) // Disable compression by default
326                                 setoptions |= SSL_OP_NO_COMPRESSION;
327 #endif
328                         // Disable TLSv1.0 by default.
329                         if (!tag->getBool("tlsv1", false))
330                                 setoptions |= SSL_OP_NO_TLSv1;
331
332                         if (!setoptions && !clearoptions)
333                                 return; // Nothing to do
334
335                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Setting %s %s context options, default: %ld set: %ld clear: %ld", name.c_str(), ctxname.c_str(), ctx.GetDefaultContextOptions(), setoptions, clearoptions);
336                         long final = context.SetRawContextOptions(setoptions, clearoptions);
337                         ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "%s %s context options: %ld", name.c_str(), ctxname.c_str(), final);
338                 }
339
340          public:
341                 Profile(const std::string& profilename, ConfigTag* tag)
342                         : name(profilename)
343                         , dh(ServerInstance->Config->Paths.PrependConfig(tag->getString("dhfile", "dhparams.pem")))
344                         , ctx(SSL_CTX_new(SSLv23_server_method()))
345                         , clictx(SSL_CTX_new(SSLv23_client_method()))
346                         , allowrenego(tag->getBool("renegotiation")) // Disallow by default
347                         , outrecsize(tag->getInt("outrecsize", 2048, 512, 16384))
348                 {
349                         if ((!ctx.SetDH(dh)) || (!clictx.SetDH(dh)))
350                                 throw Exception("Couldn't set DH parameters");
351
352                         std::string hash = tag->getString("hash", "md5");
353                         digest = EVP_get_digestbyname(hash.c_str());
354                         if (digest == NULL)
355                                 throw Exception("Unknown hash type " + hash);
356
357                         std::string ciphers = tag->getString("ciphers");
358                         if (!ciphers.empty())
359                         {
360                                 if ((!ctx.SetCiphers(ciphers)) || (!clictx.SetCiphers(ciphers)))
361                                 {
362                                         ERR_print_errors_cb(error_callback, this);
363                                         throw Exception("Can't set cipher list to \"" + ciphers + "\" " + lasterr);
364                                 }
365                         }
366
367 #ifndef OPENSSL_NO_ECDH
368                         std::string curvename = tag->getString("ecdhcurve", "prime256v1");
369                         if (!curvename.empty())
370                                 ctx.SetECDH(curvename);
371 #endif
372
373                         SetContextOptions("server", tag, ctx);
374                         SetContextOptions("client", tag, clictx);
375
376                         /* Load our keys and certificates
377                          * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.
378                          */
379                         std::string filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("certfile", "cert.pem"));
380                         if ((!ctx.SetCerts(filename)) || (!clictx.SetCerts(filename)))
381                         {
382                                 ERR_print_errors_cb(error_callback, this);
383                                 throw Exception("Can't read certificate file: " + lasterr);
384                         }
385
386                         filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("keyfile", "key.pem"));
387                         if ((!ctx.SetPrivateKey(filename)) || (!clictx.SetPrivateKey(filename)))
388                         {
389                                 ERR_print_errors_cb(error_callback, this);
390                                 throw Exception("Can't read key file: " + lasterr);
391                         }
392
393                         // Load the CAs we trust
394                         filename = ServerInstance->Config->Paths.PrependConfig(tag->getString("cafile", "ca.pem"));
395                         if ((!ctx.SetCA(filename)) || (!clictx.SetCA(filename)))
396                         {
397                                 ERR_print_errors_cb(error_callback, this);
398                                 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Can't read CA list from %s. This is only a problem if you want to verify client certificates, otherwise it's safe to ignore this message. Error: %s", filename.c_str(), lasterr.c_str());
399                         }
400
401                         // Load the CRLs.
402                         std::string crlfile  = tag->getString("crlfile");
403                         std::string crlpath  = tag->getString("crlpath");
404                         std::string crlmode  = tag->getString("crlmode", "chain");
405                         ctx.SetCRL(crlfile, crlpath, crlmode);
406
407                         clictx.SetVerifyCert();
408                         if (tag->getBool("requestclientcert", true))
409                                 ctx.SetVerifyCert();
410                 }
411
412                 const std::string& GetName() const { return name; }
413                 SSL* CreateServerSession() { return ctx.CreateServerSession(); }
414                 SSL* CreateClientSession() { return clictx.CreateClientSession(); }
415                 const EVP_MD* GetDigest() { return digest; }
416                 bool AllowRenegotiation() const { return allowrenego; }
417                 unsigned int GetOutgoingRecordSize() const { return outrecsize; }
418         };
419
420         namespace BIOMethod
421         {
422                 static int create(BIO* bio)
423                 {
424                         BIO_set_init(bio, 1);
425                         return 1;
426                 }
427
428                 static int destroy(BIO* bio)
429                 {
430                         // XXX: Dummy function to avoid a memory leak in OpenSSL.
431                         // The memory leak happens in BIO_free() (bio_lib.c) when the destroy func of the BIO is NULL.
432                         // This is fixed in OpenSSL but some distros still ship the unpatched version hence we provide this workaround.
433                         return 1;
434                 }
435
436                 static long ctrl(BIO* bio, int cmd, long num, void* ptr)
437                 {
438                         if (cmd == BIO_CTRL_FLUSH)
439                                 return 1;
440                         return 0;
441                 }
442
443                 static int read(BIO* bio, char* buf, int len);
444                 static int write(BIO* bio, const char* buf, int len);
445
446 #ifdef INSPIRCD_OPENSSL_OPAQUE_BIO
447                 static BIO_METHOD* alloc()
448                 {
449                         BIO_METHOD* meth = BIO_meth_new(100 | BIO_TYPE_SOURCE_SINK, "inspircd");
450                         BIO_meth_set_write(meth, OpenSSL::BIOMethod::write);
451                         BIO_meth_set_read(meth, OpenSSL::BIOMethod::read);
452                         BIO_meth_set_ctrl(meth, OpenSSL::BIOMethod::ctrl);
453                         BIO_meth_set_create(meth, OpenSSL::BIOMethod::create);
454                         BIO_meth_set_destroy(meth, OpenSSL::BIOMethod::destroy);
455                         return meth;
456                 }
457 #endif
458         }
459 }
460
461 // BIO_METHOD is opaque in OpenSSL 1.1 so we can't do this.
462 // See OpenSSL::BIOMethod::alloc for the new method.
463 #ifndef INSPIRCD_OPENSSL_OPAQUE_BIO
464 static BIO_METHOD biomethods =
465 {
466         (100 | BIO_TYPE_SOURCE_SINK),
467         "inspircd",
468         OpenSSL::BIOMethod::write,
469         OpenSSL::BIOMethod::read,
470         NULL, // puts
471         NULL, // gets
472         OpenSSL::BIOMethod::ctrl,
473         OpenSSL::BIOMethod::create,
474         OpenSSL::BIOMethod::destroy, // destroy, does nothing, see function body for more info
475         NULL // callback_ctrl
476 };
477 #else
478 static BIO_METHOD* biomethods;
479 #endif
480
481 static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
482 {
483         /* XXX: This will allow self signed certificates.
484          * In the future if we want an option to not allow this,
485          * we can just return preverify_ok here, and openssl
486          * will boot off self-signed and invalid peer certs.
487          */
488         int ve = X509_STORE_CTX_get_error(ctx);
489
490         SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
491
492         return 1;
493 }
494
495 class OpenSSLIOHook : public SSLIOHook
496 {
497  private:
498         SSL* sess;
499         issl_status status;
500         bool data_to_write;
501
502         // Returns 1 if handshake succeeded, 0 if it is still in progress, -1 if it failed
503         int Handshake(StreamSocket* user)
504         {
505                 ERR_clear_error();
506                 int ret = SSL_do_handshake(sess);
507                 if (ret < 0)
508                 {
509                         int err = SSL_get_error(sess, ret);
510
511                         if (err == SSL_ERROR_WANT_READ)
512                         {
513                                 SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
514                                 this->status = ISSL_HANDSHAKING;
515                                 return 0;
516                         }
517                         else if (err == SSL_ERROR_WANT_WRITE)
518                         {
519                                 SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
520                                 this->status = ISSL_HANDSHAKING;
521                                 return 0;
522                         }
523                         else
524                         {
525                                 CloseSession();
526                                 return -1;
527                         }
528                 }
529                 else if (ret > 0)
530                 {
531                         // Handshake complete.
532                         VerifyCertificate();
533
534                         status = ISSL_OPEN;
535
536                         SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
537
538                         return 1;
539                 }
540                 else if (ret == 0)
541                 {
542                         CloseSession();
543                 }
544                 return -1;
545         }
546
547         void CloseSession()
548         {
549                 if (sess)
550                 {
551                         SSL_shutdown(sess);
552                         SSL_free(sess);
553                 }
554                 sess = NULL;
555                 certificate = NULL;
556                 status = ISSL_NONE;
557         }
558
559         void VerifyCertificate()
560         {
561                 X509* cert;
562                 ssl_cert* certinfo = new ssl_cert;
563                 this->certificate = certinfo;
564                 unsigned int n;
565                 unsigned char md[EVP_MAX_MD_SIZE];
566
567                 cert = SSL_get_peer_certificate(sess);
568
569                 if (!cert)
570                 {
571                         certinfo->error = "Could not get peer certificate: "+std::string(get_error());
572                         return;
573                 }
574
575                 certinfo->invalid = (SSL_get_verify_result(sess) != X509_V_OK);
576
577                 if (!SelfSigned)
578                 {
579                         certinfo->unknownsigner = false;
580                         certinfo->trusted = true;
581                 }
582                 else
583                 {
584                         certinfo->unknownsigner = true;
585                         certinfo->trusted = false;
586                 }
587
588                 char buf[512];
589                 X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
590                 certinfo->dn = buf;
591                 // Make sure there are no chars in the string that we consider invalid
592                 if (certinfo->dn.find_first_of("\r\n") != std::string::npos)
593                         certinfo->dn.clear();
594
595                 X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
596                 certinfo->issuer = buf;
597                 if (certinfo->issuer.find_first_of("\r\n") != std::string::npos)
598                         certinfo->issuer.clear();
599
600                 if (!X509_digest(cert, GetProfile().GetDigest(), md, &n))
601                 {
602                         certinfo->error = "Out of memory generating fingerprint";
603                 }
604                 else
605                 {
606                         certinfo->fingerprint = BinToHex(md, n);
607                 }
608
609                 if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), ServerInstance->Time()) == 0))
610                 {
611                         certinfo->error = "Not activated, or expired certificate";
612                 }
613
614                 X509_free(cert);
615         }
616
617         void SSLInfoCallback(int where, int rc)
618         {
619                 if ((where & SSL_CB_HANDSHAKE_START) && (status == ISSL_OPEN))
620                 {
621                         if (GetProfile().AllowRenegotiation())
622                                 return;
623
624                         // The other side is trying to renegotiate, kill the connection and change status
625                         // to ISSL_NONE so CheckRenego() closes the session
626                         status = ISSL_NONE;
627                         BIO* bio = SSL_get_rbio(sess);
628                         EventHandler* eh = static_cast<StreamSocket*>(BIO_get_data(bio));
629                         SocketEngine::Shutdown(eh, 2);
630                 }
631         }
632
633         bool CheckRenego(StreamSocket* sock)
634         {
635                 if (status != ISSL_NONE)
636                         return true;
637
638                 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Session %p killed, attempted to renegotiate", (void*)sess);
639                 CloseSession();
640                 sock->SetError("Renegotiation is not allowed");
641                 return false;
642         }
643
644         // Returns 1 if application I/O should proceed, 0 if it must wait for the underlying protocol to progress, -1 on fatal error
645         int PrepareIO(StreamSocket* sock)
646         {
647                 if (status == ISSL_OPEN)
648                         return 1;
649                 else if (status == ISSL_HANDSHAKING)
650                 {
651                         // The handshake isn't finished, try to finish it
652                         return Handshake(sock);
653                 }
654
655                 CloseSession();
656                 return -1;
657         }
658
659         // Calls our private SSLInfoCallback()
660         friend void StaticSSLInfoCallback(const SSL* ssl, int where, int rc);
661
662  public:
663         OpenSSLIOHook(IOHookProvider* hookprov, StreamSocket* sock, SSL* session)
664                 : SSLIOHook(hookprov)
665                 , sess(session)
666                 , status(ISSL_NONE)
667                 , data_to_write(false)
668         {
669                 // Create BIO instance and store a pointer to the socket in it which will be used by the read and write functions
670 #ifdef INSPIRCD_OPENSSL_OPAQUE_BIO
671                 BIO* bio = BIO_new(biomethods);
672 #else
673                 BIO* bio = BIO_new(&biomethods);
674 #endif
675                 BIO_set_data(bio, sock);
676                 SSL_set_bio(sess, bio, bio);
677
678                 SSL_set_ex_data(sess, exdataindex, this);
679                 sock->AddIOHook(this);
680                 Handshake(sock);
681         }
682
683         void OnStreamSocketClose(StreamSocket* user) CXX11_OVERRIDE
684         {
685                 CloseSession();
686         }
687
688         int OnStreamSocketRead(StreamSocket* user, std::string& recvq) CXX11_OVERRIDE
689         {
690                 // Finish handshake if needed
691                 int prepret = PrepareIO(user);
692                 if (prepret <= 0)
693                         return prepret;
694
695                 // If we resumed the handshake then this->status will be ISSL_OPEN
696                 {
697                         ERR_clear_error();
698                         char* buffer = ServerInstance->GetReadBuffer();
699                         size_t bufsiz = ServerInstance->Config->NetBufferSize;
700                         int ret = SSL_read(sess, buffer, bufsiz);
701
702                         if (!CheckRenego(user))
703                                 return -1;
704
705                         if (ret > 0)
706                         {
707                                 recvq.append(buffer, ret);
708                                 int mask = 0;
709                                 // Schedule a read if there is still data in the OpenSSL buffer
710                                 if (SSL_pending(sess) > 0)
711                                         mask |= FD_ADD_TRIAL_READ;
712                                 if (data_to_write)
713                                         mask |= FD_WANT_POLL_READ | FD_WANT_SINGLE_WRITE;
714                                 if (mask != 0)
715                                         SocketEngine::ChangeEventMask(user, mask);
716                                 return 1;
717                         }
718                         else if (ret == 0)
719                         {
720                                 // Client closed connection.
721                                 CloseSession();
722                                 user->SetError("Connection closed");
723                                 return -1;
724                         }
725                         else // if (ret < 0)
726                         {
727                                 int err = SSL_get_error(sess, ret);
728
729                                 if (err == SSL_ERROR_WANT_READ)
730                                 {
731                                         SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ);
732                                         return 0;
733                                 }
734                                 else if (err == SSL_ERROR_WANT_WRITE)
735                                 {
736                                         SocketEngine::ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
737                                         return 0;
738                                 }
739                                 else
740                                 {
741                                         CloseSession();
742                                         return -1;
743                                 }
744                         }
745                 }
746         }
747
748         int OnStreamSocketWrite(StreamSocket* user, StreamSocket::SendQueue& sendq) CXX11_OVERRIDE
749         {
750                 // Finish handshake if needed
751                 int prepret = PrepareIO(user);
752                 if (prepret <= 0)
753                         return prepret;
754
755                 data_to_write = true;
756
757                 // Session is ready for transferring application data
758                 while (!sendq.empty())
759                 {
760                         ERR_clear_error();
761                         FlattenSendQueue(sendq, GetProfile().GetOutgoingRecordSize());
762                         const StreamSocket::SendQueue::Element& buffer = sendq.front();
763                         int ret = SSL_write(sess, buffer.data(), buffer.size());
764
765                         if (!CheckRenego(user))
766                                 return -1;
767
768                         if (ret == (int)buffer.length())
769                         {
770                                 // Wrote entire record, continue sending
771                                 sendq.pop_front();
772                         }
773                         else if (ret > 0)
774                         {
775                                 sendq.erase_front(ret);
776                                 SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
777                                 return 0;
778                         }
779                         else if (ret == 0)
780                         {
781                                 CloseSession();
782                                 return -1;
783                         }
784                         else // if (ret < 0)
785                         {
786                                 int err = SSL_get_error(sess, ret);
787
788                                 if (err == SSL_ERROR_WANT_WRITE)
789                                 {
790                                         SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
791                                         return 0;
792                                 }
793                                 else if (err == SSL_ERROR_WANT_READ)
794                                 {
795                                         SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ);
796                                         return 0;
797                                 }
798                                 else
799                                 {
800                                         CloseSession();
801                                         return -1;
802                                 }
803                         }
804                 }
805
806                 data_to_write = false;
807                 SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
808                 return 1;
809         }
810
811         void GetCiphersuite(std::string& out) const CXX11_OVERRIDE
812         {
813                 if (!IsHandshakeDone())
814                         return;
815                 out.append(SSL_get_version(sess)).push_back('-');
816                 out.append(SSL_get_cipher(sess));
817         }
818
819         bool GetServerName(std::string& out) const CXX11_OVERRIDE
820         {
821                 const char* name = SSL_get_servername(sess, TLSEXT_NAMETYPE_host_name);
822                 if (!name)
823                         return false;
824
825                 out.append(name);
826                 return true;
827         }
828
829         bool IsHandshakeDone() const { return (status == ISSL_OPEN); }
830         OpenSSL::Profile& GetProfile();
831 };
832
833 static void StaticSSLInfoCallback(const SSL* ssl, int where, int rc)
834 {
835         OpenSSLIOHook* hook = static_cast<OpenSSLIOHook*>(SSL_get_ex_data(ssl, exdataindex));
836         hook->SSLInfoCallback(where, rc);
837 }
838
839 static int OpenSSL::BIOMethod::write(BIO* bio, const char* buffer, int size)
840 {
841         BIO_clear_retry_flags(bio);
842
843         StreamSocket* sock = static_cast<StreamSocket*>(BIO_get_data(bio));
844         if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK)
845         {
846                 // Writes blocked earlier, don't retry syscall
847                 BIO_set_retry_write(bio);
848                 return -1;
849         }
850
851         int ret = SocketEngine::Send(sock, buffer, size, 0);
852         if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError())))
853         {
854                 // Blocked, set retry flag for OpenSSL
855                 SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK);
856                 BIO_set_retry_write(bio);
857         }
858
859         return ret;
860 }
861
862 static int OpenSSL::BIOMethod::read(BIO* bio, char* buffer, int size)
863 {
864         BIO_clear_retry_flags(bio);
865
866         StreamSocket* sock = static_cast<StreamSocket*>(BIO_get_data(bio));
867         if (sock->GetEventMask() & FD_READ_WILL_BLOCK)
868         {
869                 // Reads blocked earlier, don't retry syscall
870                 BIO_set_retry_read(bio);
871                 return -1;
872         }
873
874         int ret = SocketEngine::Recv(sock, buffer, size, 0);
875         if ((ret < size) && ((ret > 0) || (SocketEngine::IgnoreError())))
876         {
877                 // Blocked, set retry flag for OpenSSL
878                 SocketEngine::ChangeEventMask(sock, FD_READ_WILL_BLOCK);
879                 BIO_set_retry_read(bio);
880         }
881
882         return ret;
883 }
884
885 class OpenSSLIOHookProvider : public IOHookProvider
886 {
887         OpenSSL::Profile profile;
888
889  public:
890         OpenSSLIOHookProvider(Module* mod, const std::string& profilename, ConfigTag* tag)
891                 : IOHookProvider(mod, "ssl/" + profilename, IOHookProvider::IOH_SSL)
892                 , profile(profilename, tag)
893         {
894                 ServerInstance->Modules->AddService(*this);
895         }
896
897         ~OpenSSLIOHookProvider()
898         {
899                 ServerInstance->Modules->DelService(*this);
900         }
901
902         void OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
903         {
904                 new OpenSSLIOHook(this, sock, profile.CreateServerSession());
905         }
906
907         void OnConnect(StreamSocket* sock) CXX11_OVERRIDE
908         {
909                 new OpenSSLIOHook(this, sock, profile.CreateClientSession());
910         }
911
912         OpenSSL::Profile& GetProfile() { return profile; }
913 };
914
915 OpenSSL::Profile& OpenSSLIOHook::GetProfile()
916 {
917         IOHookProvider* hookprov = prov;
918         return static_cast<OpenSSLIOHookProvider*>(hookprov)->GetProfile();
919 }
920
921 class ModuleSSLOpenSSL : public Module
922 {
923         typedef std::vector<reference<OpenSSLIOHookProvider> > ProfileList;
924
925         ProfileList profiles;
926
927         void ReadProfiles()
928         {
929                 ProfileList newprofiles;
930                 ConfigTagList tags = ServerInstance->Config->ConfTags("sslprofile");
931                 if (tags.first == tags.second)
932                 {
933                         // Create a default profile named "openssl"
934                         const std::string defname = "openssl";
935                         ConfigTag* tag = ServerInstance->Config->ConfValue(defname);
936                         ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "No <sslprofile> tags found, using settings from the <openssl> tag");
937
938                         try
939                         {
940                                 newprofiles.push_back(new OpenSSLIOHookProvider(this, defname, tag));
941                         }
942                         catch (OpenSSL::Exception& ex)
943                         {
944                                 throw ModuleException("Error while initializing the default SSL profile - " + ex.GetReason());
945                         }
946                 }
947
948                 for (ConfigIter i = tags.first; i != tags.second; ++i)
949                 {
950                         ConfigTag* tag = i->second;
951                         if (tag->getString("provider") != "openssl")
952                                 continue;
953
954                         std::string name = tag->getString("name");
955                         if (name.empty())
956                         {
957                                 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Ignoring <sslprofile> tag without name at " + tag->getTagLocation());
958                                 continue;
959                         }
960
961                         reference<OpenSSLIOHookProvider> prov;
962                         try
963                         {
964                                 prov = new OpenSSLIOHookProvider(this, name, tag);
965                         }
966                         catch (CoreException& ex)
967                         {
968                                 throw ModuleException("Error while initializing SSL profile \"" + name + "\" at " + tag->getTagLocation() + " - " + ex.GetReason());
969                         }
970
971                         newprofiles.push_back(prov);
972                 }
973
974                 for (ProfileList::iterator i = profiles.begin(); i != profiles.end(); ++i)
975                 {
976                         OpenSSLIOHookProvider& prov = **i;
977                         ServerInstance->Modules.DelService(prov);
978                 }
979
980                 profiles.swap(newprofiles);
981         }
982
983  public:
984         ModuleSSLOpenSSL()
985         {
986                 // Initialize OpenSSL
987                 SSL_library_init();
988                 SSL_load_error_strings();
989 #ifdef INSPIRCD_OPENSSL_OPAQUE_BIO
990                 biomethods = OpenSSL::BIOMethod::alloc();
991         }
992
993         ~ModuleSSLOpenSSL()
994         {
995                 BIO_meth_free(biomethods);
996 #endif
997         }
998
999         void init() CXX11_OVERRIDE
1000         {
1001                 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "OpenSSL lib version \"%s\" module was compiled for \"" OPENSSL_VERSION_TEXT "\"", SSLeay_version(SSLEAY_VERSION));
1002
1003                 // Register application specific data
1004                 char exdatastr[] = "inspircd";
1005                 exdataindex = SSL_get_ex_new_index(0, exdatastr, NULL, NULL, NULL);
1006                 if (exdataindex < 0)
1007                         throw ModuleException("Failed to register application specific data");
1008
1009                 ReadProfiles();
1010         }
1011
1012         void OnModuleRehash(User* user, const std::string &param) CXX11_OVERRIDE
1013         {
1014                 if (param != "ssl")
1015                         return;
1016
1017                 try
1018                 {
1019                         ReadProfiles();
1020                 }
1021                 catch (ModuleException& ex)
1022                 {
1023                         ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, ex.GetReason() + " Not applying settings.");
1024                 }
1025         }
1026
1027         void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE
1028         {
1029                 if (type == ExtensionItem::EXT_USER)
1030                 {
1031                         LocalUser* user = IS_LOCAL((User*)item);
1032
1033                         if ((user) && (user->eh.GetModHook(this)))
1034                         {
1035                                 // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
1036                                 // Potentially there could be multiple SSL modules loaded at once on different ports.
1037                                 ServerInstance->Users->QuitUser(user, "SSL module unloading");
1038                         }
1039                 }
1040         }
1041
1042         ModResult OnCheckReady(LocalUser* user) CXX11_OVERRIDE
1043         {
1044                 const OpenSSLIOHook* const iohook = static_cast<OpenSSLIOHook*>(user->eh.GetModHook(this));
1045                 if ((iohook) && (!iohook->IsHandshakeDone()))
1046                         return MOD_RES_DENY;
1047                 return MOD_RES_PASSTHRU;
1048         }
1049
1050         Version GetVersion() CXX11_OVERRIDE
1051         {
1052                 return Version("Provides SSL support for clients", VF_VENDOR);
1053         }
1054 };
1055
1056 MODULE_INIT(ModuleSSLOpenSSL)