]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_ssl_openssl.cpp
37d2a9cdfe128ff6ed12f4a4392fcb81aa3cef5f
[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  /* HACK: This prevents OpenSSL on OS X 10.7 and later from spewing deprecation
25   * warnings for every single function call. As far as I (SaberUK) know, Apple
26   * have no plans to remove OpenSSL so this warning just causes needless spam.
27   */
28 #ifdef __APPLE__
29 # define __AVAILABILITYMACROS__
30 # define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
31 #endif
32  
33 #include "inspircd.h"
34 #include <openssl/ssl.h>
35 #include <openssl/err.h>
36 #include "ssl.h"
37
38 #ifdef _WIN32
39 # pragma comment(lib, "ssleay32.lib")
40 # pragma comment(lib, "libeay32.lib")
41 # undef MAX_DESCRIPTORS
42 # define MAX_DESCRIPTORS 10000
43 #endif
44
45 /* $ModDesc: Provides SSL support for clients */
46
47 /* $LinkerFlags: if("USE_FREEBSD_BASE_SSL") -lssl -lcrypto */
48 /* $CompileFlags: if(!"USE_FREEBSD_BASE_SSL") pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */
49 /* $LinkerFlags: if(!"USE_FREEBSD_BASE_SSL") rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto -ldl") */
50
51 /* $NoPedantic */
52
53
54 enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
55
56 static bool SelfSigned = false;
57
58 char* get_error()
59 {
60         return ERR_error_string(ERR_get_error(), NULL);
61 }
62
63 static int error_callback(const char *str, size_t len, void *u);
64
65 /** Represents an SSL user's extra data
66  */
67 class issl_session
68 {
69 public:
70         SSL* sess;
71         issl_status status;
72         reference<ssl_cert> cert;
73
74         bool outbound;
75         bool data_to_write;
76
77         issl_session()
78         {
79                 outbound = false;
80                 data_to_write = false;
81         }
82 };
83
84 static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
85 {
86         /* XXX: This will allow self signed certificates.
87          * In the future if we want an option to not allow this,
88          * we can just return preverify_ok here, and openssl
89          * will boot off self-signed and invalid peer certs.
90          */
91         int ve = X509_STORE_CTX_get_error(ctx);
92
93         SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
94
95         return 1;
96 }
97
98 class ModuleSSLOpenSSL : public Module
99 {
100         issl_session* sessions;
101
102         SSL_CTX* ctx;
103         SSL_CTX* clictx;
104
105         std::string sslports;
106         bool use_sha;
107
108         ServiceProvider iohook;
109  public:
110
111         ModuleSSLOpenSSL() : iohook(this, "ssl/openssl", SERVICE_IOHOOK)
112         {
113                 sessions = new issl_session[ServerInstance->SE->GetMaxFds()];
114
115                 /* Global SSL library initialization*/
116                 SSL_library_init();
117                 SSL_load_error_strings();
118
119                 /* Build our SSL contexts:
120                  * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK.
121                  */
122                 ctx = SSL_CTX_new( SSLv23_server_method() );
123                 clictx = SSL_CTX_new( SSLv23_client_method() );
124
125                 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
126                 SSL_CTX_set_mode(clictx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
127
128                 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
129                 SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
130
131                 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
132                 SSL_CTX_set_session_cache_mode(clictx, SSL_SESS_CACHE_OFF);
133
134                 long opts = SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE;
135                 // Only turn options on if they exist
136 #ifdef SSL_OP_SINGLE_ECDH_USE
137                 opts |= SSL_OP_SINGLE_ECDH_USE;
138 #endif
139 #ifdef SSL_OP_NO_TICKET
140                 opts |= SSL_OP_NO_TICKET;
141 #endif
142
143                 SSL_CTX_set_options(ctx, opts);
144                 SSL_CTX_set_options(clictx, opts);
145         }
146
147         void init()
148         {
149                 // Needs the flag as it ignores a plain /rehash
150                 OnModuleRehash(NULL,"ssl");
151                 Implementation eventlist[] = { I_On005Numeric, I_OnRehash, I_OnModuleRehash, I_OnHookIO, I_OnUserConnect };
152                 ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
153                 ServerInstance->Modules->AddService(iohook);
154         }
155
156         void OnHookIO(StreamSocket* user, ListenSocket* lsb)
157         {
158                 if (!user->GetIOHook() && lsb->bind_tag->getString("ssl") == "openssl")
159                 {
160                         /* Hook the user with our module */
161                         user->AddIOHook(this);
162                 }
163         }
164
165         void OnRehash(User* user)
166         {
167                 sslports.clear();
168
169                 ConfigTag* Conf = ServerInstance->Config->ConfValue("openssl");
170
171                 if (Conf->getBool("showports", true))
172                 {
173                         sslports = Conf->getString("advertisedports");
174                         if (!sslports.empty())
175                                 return;
176
177                         for (size_t i = 0; i < ServerInstance->ports.size(); i++)
178                         {
179                                 ListenSocket* port = ServerInstance->ports[i];
180                                 if (port->bind_tag->getString("ssl") != "openssl")
181                                         continue;
182
183                                 const std::string& portid = port->bind_desc;
184                                 ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %s", portid.c_str());
185
186                                 if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1")
187                                 {
188                                         /*
189                                          * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display
190                                          * the IP:port in ISUPPORT.
191                                          *
192                                          * We used to advertise all ports seperated by a ';' char that matched the above criteria,
193                                          * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed.
194                                          * To solve this by default we now only display the first IP:port found and let the user
195                                          * configure the exact value for the 005 token, if necessary.
196                                          */
197                                         sslports = portid;
198                                         break;
199                                 }
200                         }
201                 }
202         }
203
204         void OnModuleRehash(User* user, const std::string &param)
205         {
206                 if (param != "ssl")
207                         return;
208
209                 std::string keyfile;
210                 std::string certfile;
211                 std::string cafile;
212                 std::string dhfile;
213                 OnRehash(user);
214
215                 ConfigTag* conf = ServerInstance->Config->ConfValue("openssl");
216
217                 cafile   = conf->getString("cafile", CONFIG_PATH "/ca.pem");
218                 certfile = conf->getString("certfile", CONFIG_PATH "/cert.pem");
219                 keyfile  = conf->getString("keyfile", CONFIG_PATH "/key.pem");
220                 dhfile   = conf->getString("dhfile", CONFIG_PATH "/dhparams.pem");
221                 std::string hash = conf->getString("hash", "md5");
222                 if (hash != "sha1" && hash != "md5")
223                         throw ModuleException("Unknown hash type " + hash);
224                 use_sha = (hash == "sha1");
225
226                 std::string ciphers = conf->getString("ciphers", "");
227
228                 if (!ciphers.empty())
229                 {
230                         ERR_clear_error();
231                         if ((!SSL_CTX_set_cipher_list(ctx, ciphers.c_str())) || (!SSL_CTX_set_cipher_list(clictx, ciphers.c_str())))
232                         {
233                                 ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't set cipher list to %s.", ciphers.c_str());
234                                 ERR_print_errors_cb(error_callback, this);
235                         }
236                 }
237
238                 /* Load our keys and certificates
239                  * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.
240                  */
241                 ERR_clear_error();
242                 if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str())))
243                 {
244                         ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno));
245                         ERR_print_errors_cb(error_callback, this);
246                 }
247
248                 ERR_clear_error();
249                 if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM)))
250                 {
251                         ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno));
252                         ERR_print_errors_cb(error_callback, this);
253                 }
254
255                 /* Load the CAs we trust*/
256                 ERR_clear_error();
257                 if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0)))
258                 {
259                         ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: 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", cafile.c_str(), strerror(errno));
260                         ERR_print_errors_cb(error_callback, this);
261                 }
262
263 #ifdef _WIN32
264                 BIO* dhpfile = BIO_new_file(dhfile.c_str(), "r");
265 #else
266                 FILE* dhpfile = fopen(dhfile.c_str(), "r");
267 #endif
268                 DH* ret;
269
270                 if (dhpfile == NULL)
271                 {
272                         ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno));
273                         throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno));
274                 }
275                 else
276                 {
277 #ifdef _WIN32
278                         ret = PEM_read_bio_DHparams(dhpfile, NULL, NULL, NULL);
279                         BIO_free(dhpfile);
280 #else
281                         ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
282 #endif
283
284                         ERR_clear_error();
285                         if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0))
286                         {
287                                 ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str());
288                                 ERR_print_errors_cb(error_callback, this);
289                         }
290                         DH_free(ret);
291                 }
292
293 #ifndef _WIN32
294                 fclose(dhpfile);
295 #endif
296         }
297
298         void On005Numeric(std::string &output)
299         {
300                 if (!sslports.empty())
301                         output.append(" SSL=" + sslports);
302         }
303
304         ~ModuleSSLOpenSSL()
305         {
306                 SSL_CTX_free(ctx);
307                 SSL_CTX_free(clictx);
308                 delete[] sessions;
309         }
310
311         void OnUserConnect(LocalUser* user)
312         {
313                 if (user->eh.GetIOHook() == this)
314                 {
315                         if (sessions[user->eh.GetFd()].sess)
316                         {
317                                 if (!sessions[user->eh.GetFd()].cert->fingerprint.empty())
318                                         user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\""
319                                                 " and your SSL fingerprint is %s", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess), sessions[user->eh.GetFd()].cert->fingerprint.c_str());
320                                 else
321                                         user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess));
322                         }
323                 }
324         }
325
326         void OnCleanup(int target_type, void* item)
327         {
328                 if (target_type == TYPE_USER)
329                 {
330                         LocalUser* user = IS_LOCAL((User*)item);
331
332                         if (user && user->eh.GetIOHook() == this)
333                         {
334                                 // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
335                                 // Potentially there could be multiple SSL modules loaded at once on different ports.
336                                 ServerInstance->Users->QuitUser(user, "SSL module unloading");
337                         }
338                 }
339         }
340
341         Version GetVersion()
342         {
343                 return Version("Provides SSL support for clients", VF_VENDOR);
344         }
345
346         void OnRequest(Request& request)
347         {
348                 if (strcmp("GET_SSL_CERT", request.id) == 0)
349                 {
350                         SocketCertificateRequest& req = static_cast<SocketCertificateRequest&>(request);
351                         int fd = req.sock->GetFd();
352                         issl_session* session = &sessions[fd];
353
354                         req.cert = session->cert;
355                 }
356         }
357
358         void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
359         {
360                 int fd = user->GetFd();
361
362                 issl_session* session = &sessions[fd];
363
364                 session->sess = SSL_new(ctx);
365                 session->status = ISSL_NONE;
366                 session->outbound = false;
367                 session->cert = NULL;
368
369                 if (session->sess == NULL)
370                         return;
371
372                 if (SSL_set_fd(session->sess, fd) == 0)
373                 {
374                         ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
375                         return;
376                 }
377
378                 Handshake(user, session);
379         }
380
381         void OnStreamSocketConnect(StreamSocket* user)
382         {
383                 int fd = user->GetFd();
384                 /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
385                 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() -1))
386                         return;
387
388                 issl_session* session = &sessions[fd];
389
390                 session->sess = SSL_new(clictx);
391                 session->status = ISSL_NONE;
392                 session->outbound = true;
393
394                 if (session->sess == NULL)
395                         return;
396
397                 if (SSL_set_fd(session->sess, fd) == 0)
398                 {
399                         ServerInstance->Logs->Log("m_ssl_openssl",DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
400                         return;
401                 }
402
403                 Handshake(user, session);
404         }
405
406         void OnStreamSocketClose(StreamSocket* user)
407         {
408                 int fd = user->GetFd();
409                 /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
410                 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
411                         return;
412
413                 CloseSession(&sessions[fd]);
414         }
415
416         int OnStreamSocketRead(StreamSocket* user, std::string& recvq)
417         {
418                 int fd = user->GetFd();
419                 /* Are there any possibilities of an out of range fd? Hope not, but lets be paranoid */
420                 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
421                         return -1;
422
423                 issl_session* session = &sessions[fd];
424
425                 if (!session->sess)
426                 {
427                         CloseSession(session);
428                         return -1;
429                 }
430
431                 if (session->status == ISSL_HANDSHAKING)
432                 {
433                         // The handshake isn't finished and it wants to read, try to finish it.
434                         if (!Handshake(user, session))
435                         {
436                                 // Couldn't resume handshake.
437                                 if (session->status == ISSL_NONE)
438                                         return -1;
439                                 return 0;
440                         }
441                 }
442
443                 // If we resumed the handshake then session->status will be ISSL_OPEN
444
445                 if (session->status == ISSL_OPEN)
446                 {
447                         ERR_clear_error();
448                         char* buffer = ServerInstance->GetReadBuffer();
449                         size_t bufsiz = ServerInstance->Config->NetBufferSize;
450                         int ret = SSL_read(session->sess, buffer, bufsiz);
451
452                         if (ret > 0)
453                         {
454                                 recvq.append(buffer, ret);
455                                 if (session->data_to_write)
456                                         ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_SINGLE_WRITE);
457                                 return 1;
458                         }
459                         else if (ret == 0)
460                         {
461                                 // Client closed connection.
462                                 CloseSession(session);
463                                 user->SetError("Connection closed");
464                                 return -1;
465                         }
466                         else if (ret < 0)
467                         {
468                                 int err = SSL_get_error(session->sess, ret);
469
470                                 if (err == SSL_ERROR_WANT_READ)
471                                 {
472                                         ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ);
473                                         return 0;
474                                 }
475                                 else if (err == SSL_ERROR_WANT_WRITE)
476                                 {
477                                         ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
478                                         return 0;
479                                 }
480                                 else
481                                 {
482                                         CloseSession(session);
483                                         return -1;
484                                 }
485                         }
486                 }
487
488                 return 0;
489         }
490
491         int OnStreamSocketWrite(StreamSocket* user, std::string& buffer)
492         {
493                 int fd = user->GetFd();
494
495                 issl_session* session = &sessions[fd];
496
497                 if (!session->sess)
498                 {
499                         CloseSession(session);
500                         return -1;
501                 }
502
503                 session->data_to_write = true;
504
505                 if (session->status == ISSL_HANDSHAKING)
506                 {
507                         if (!Handshake(user, session))
508                         {
509                                 // Couldn't resume handshake.
510                                 if (session->status == ISSL_NONE)
511                                         return -1;
512                                 return 0;
513                         }
514                 }
515
516                 if (session->status == ISSL_OPEN)
517                 {
518                         ERR_clear_error();
519                         int ret = SSL_write(session->sess, buffer.data(), buffer.size());
520                         if (ret == (int)buffer.length())
521                         {
522                                 session->data_to_write = false;
523                                 ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
524                                 return 1;
525                         }
526                         else if (ret > 0)
527                         {
528                                 buffer = buffer.substr(ret);
529                                 ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
530                                 return 0;
531                         }
532                         else if (ret == 0)
533                         {
534                                 CloseSession(session);
535                                 return -1;
536                         }
537                         else if (ret < 0)
538                         {
539                                 int err = SSL_get_error(session->sess, ret);
540
541                                 if (err == SSL_ERROR_WANT_WRITE)
542                                 {
543                                         ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
544                                         return 0;
545                                 }
546                                 else if (err == SSL_ERROR_WANT_READ)
547                                 {
548                                         ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ);
549                                         return 0;
550                                 }
551                                 else
552                                 {
553                                         CloseSession(session);
554                                         return -1;
555                                 }
556                         }
557                 }
558                 return 0;
559         }
560
561         bool Handshake(StreamSocket* user, issl_session* session)
562         {
563                 int ret;
564
565                 ERR_clear_error();
566                 if (session->outbound)
567                         ret = SSL_connect(session->sess);
568                 else
569                         ret = SSL_accept(session->sess);
570
571                 if (ret < 0)
572                 {
573                         int err = SSL_get_error(session->sess, ret);
574
575                         if (err == SSL_ERROR_WANT_READ)
576                         {
577                                 ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
578                                 session->status = ISSL_HANDSHAKING;
579                                 return true;
580                         }
581                         else if (err == SSL_ERROR_WANT_WRITE)
582                         {
583                                 ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
584                                 session->status = ISSL_HANDSHAKING;
585                                 return true;
586                         }
587                         else
588                         {
589                                 CloseSession(session);
590                         }
591
592                         return false;
593                 }
594                 else if (ret > 0)
595                 {
596                         // Handshake complete.
597                         VerifyCertificate(session, user);
598
599                         session->status = ISSL_OPEN;
600
601                         ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE | FD_ADD_TRIAL_WRITE);
602
603                         return true;
604                 }
605                 else if (ret == 0)
606                 {
607                         CloseSession(session);
608                         return true;
609                 }
610
611                 return true;
612         }
613
614         void CloseSession(issl_session* session)
615         {
616                 if (session->sess)
617                 {
618                         SSL_shutdown(session->sess);
619                         SSL_free(session->sess);
620                 }
621
622                 session->sess = NULL;
623                 session->status = ISSL_NONE;
624                 errno = EIO;
625         }
626
627         void VerifyCertificate(issl_session* session, StreamSocket* user)
628         {
629                 if (!session->sess || !user)
630                         return;
631
632                 X509* cert;
633                 ssl_cert* certinfo = new ssl_cert;
634                 session->cert = certinfo;
635                 unsigned int n;
636                 unsigned char md[EVP_MAX_MD_SIZE];
637                 const EVP_MD *digest = use_sha ? EVP_sha1() : EVP_md5();
638
639                 cert = SSL_get_peer_certificate((SSL*)session->sess);
640
641                 if (!cert)
642                 {
643                         certinfo->error = "Could not get peer certificate: "+std::string(get_error());
644                         return;
645                 }
646
647                 certinfo->invalid = (SSL_get_verify_result(session->sess) != X509_V_OK);
648
649                 if (!SelfSigned)
650                 {
651                         certinfo->unknownsigner = false;
652                         certinfo->trusted = true;
653                 }
654                 else
655                 {
656                         certinfo->unknownsigner = true;
657                         certinfo->trusted = false;
658                 }
659
660                 char buf[512];
661                 X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
662                 certinfo->dn = buf;
663                 // Make sure there are no chars in the string that we consider invalid
664                 if (certinfo->dn.find_first_of("\r\n") != std::string::npos)
665                         certinfo->dn.clear();
666
667                 X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
668                 certinfo->issuer = buf;
669                 if (certinfo->issuer.find_first_of("\r\n") != std::string::npos)
670                         certinfo->issuer.clear();
671
672                 if (!X509_digest(cert, digest, md, &n))
673                 {
674                         certinfo->error = "Out of memory generating fingerprint";
675                 }
676                 else
677                 {
678                         certinfo->fingerprint = irc::hex(md, n);
679                 }
680
681                 if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), ServerInstance->Time()) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), ServerInstance->Time()) == 0))
682                 {
683                         certinfo->error = "Not activated, or expired certificate";
684                 }
685
686                 X509_free(cert);
687         }
688 };
689
690 static int error_callback(const char *str, size_t len, void *u)
691 {
692         ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "SSL error: " + std::string(str, len - 1));
693
694         //
695         // XXX: Remove this line, it causes valgrind warnings...
696         //
697         // MD_update(&m, buf, j);
698         //
699         //
700         // ... ONLY JOKING! :-)
701         //
702
703         return 0;
704 }
705
706 MODULE_INIT(ModuleSSLOpenSSL)