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