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