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