]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_ssl_openssl.cpp
Dont report that the key has expired when it hasnt
[user/henk/code/inspircd.git] / src / modules / extra / m_ssl_openssl.cpp
1 #include <string>
2 #include <vector>
3
4 #include <openssl/ssl.h>
5 #include <openssl/err.h>
6
7 #include "inspircd_config.h"
8 #include "configreader.h"
9 #include "users.h"
10 #include "channels.h"
11 #include "modules.h"
12
13 #include "socket.h"
14 #include "hashcomp.h"
15 #include "inspircd.h"
16
17 #include "ssl_cert.h"
18
19 /* $ModDesc: Provides SSL support for clients */
20 /* $CompileFlags: -I/usr/include -I/usr/local/include */
21 /* $LinkerFlags: -L/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib -L/usr/lib -Wl,--rpath -Wl,/usr/lib -lssl */
22
23
24
25 enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
26 enum issl_io_status { ISSL_WRITE, ISSL_READ };
27
28 bool isin(int port, const std::vector<int> &portlist)
29 {
30         for(unsigned int i = 0; i < portlist.size(); i++)
31                 if(portlist[i] == port)
32                         return true;
33                         
34         return false;
35 }
36
37 char* get_error()
38 {
39         return ERR_error_string(ERR_get_error(), NULL);
40 }
41
42 class issl_session : public classbase
43 {
44 public:
45         SSL* sess;
46         issl_status status;
47         issl_io_status rstat;
48         issl_io_status wstat;
49
50         unsigned int inbufoffset;
51         char* inbuf;                    // Buffer OpenSSL reads into.
52         std::string outbuf;     // Buffer for outgoing data that OpenSSL will not take.
53         int fd;
54         
55         issl_session()
56         {
57                 rstat = ISSL_READ;
58                 wstat = ISSL_WRITE;
59         }
60 };
61
62 static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
63 {
64         /* XXX: This will allow self signed certificates.
65          * In the future if we want an option to not allow this,
66          * we can just return preverify_ok here, and openssl
67          * will boot off self-signed and invalid peer certs.
68          */
69         return 1;
70 }
71         
72 class ModuleSSLOpenSSL : public Module
73 {
74         
75         ConfigReader* Conf;
76         
77         CullList* culllist;
78         
79         std::vector<int> listenports;
80         
81         int inbufsize;
82         issl_session sessions[MAX_DESCRIPTORS];
83         
84         SSL_CTX* ctx;
85         
86         char* dummy;
87         
88         std::string keyfile;
89         std::string certfile;
90         std::string cafile;
91         // std::string crlfile;
92         std::string dhfile;
93         
94  public:
95         
96         ModuleSSLOpenSSL(InspIRCd* Me)
97                 : Module::Module(Me)
98         {
99                 culllist = new CullList(ServerInstance);
100                 
101                 // Not rehashable...because I cba to reduce all the sizes of existing buffers.
102                 inbufsize = ServerInstance->Config->NetBufferSize;
103                 
104                 /* Global SSL library initialization*/
105                 SSL_library_init();
106                 SSL_load_error_strings();
107                 
108                 /* Build our SSL context*/
109                 ctx = SSL_CTX_new( SSLv23_server_method() );
110
111                 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
112
113                 // Needs the flag as it ignores a plain /rehash
114                 OnRehash("ssl");
115         }
116         
117         virtual void OnRehash(const std::string &param)
118         {
119                 if(param != "ssl")
120                         return;
121         
122                 Conf = new ConfigReader(ServerInstance);
123                         
124                 for(unsigned int i = 0; i < listenports.size(); i++)
125                 {
126                         ServerInstance->Config->DelIOHook(listenports[i]);
127                 }
128                 
129                 listenports.clear();
130                 
131                 for(int i = 0; i < Conf->Enumerate("bind"); i++)
132                 {
133                         // For each <bind> tag
134                         if(((Conf->ReadValue("bind", "type", i) == "") || (Conf->ReadValue("bind", "type", i) == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "openssl"))
135                         {
136                                 // Get the port we're meant to be listening on with SSL
137                                 unsigned int port = Conf->ReadInteger("bind", "port", i, true);
138                                 if (ServerInstance->Config->AddIOHook(port, this))
139                                 {
140                                         // We keep a record of which ports we're listening on with SSL
141                                         listenports.push_back(port);
142                                 
143                                         ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %d", port);
144                                 }
145                                 else
146                                 {
147                                         ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", port);
148                                 }
149                         }
150                 }
151                 
152                 std::string confdir(CONFIG_FILE);
153                 // +1 so we the path ends with a /
154                 confdir = confdir.substr(0, confdir.find_last_of('/') + 1);
155                 
156                 cafile  = Conf->ReadValue("openssl", "cafile", 0);
157                 // crlfile      = Conf->ReadValue("openssl", "crlfile", 0);
158                 certfile        = Conf->ReadValue("openssl", "certfile", 0);
159                 keyfile = Conf->ReadValue("openssl", "keyfile", 0);
160                 dhfile  = Conf->ReadValue("openssl", "dhfile", 0);
161                 
162                 // Set all the default values needed.
163                 if(cafile == "")
164                         cafile = "ca.pem";
165                         
166                 //if(crlfile == "")
167                 //      crlfile = "crl.pem";
168                         
169                 if(certfile == "")
170                         certfile = "cert.pem";
171                         
172                 if(keyfile == "")
173                         keyfile = "key.pem";
174                         
175                 if(dhfile == "")
176                         dhfile = "dhparams.pem";
177                         
178                 // Prepend relative paths with the path to the config directory.        
179                 if(cafile[0] != '/')
180                         cafile = confdir + cafile;
181                 
182                 //if(crlfile[0] != '/')
183                 //      crlfile = confdir + crlfile;
184                         
185                 if(certfile[0] != '/')
186                         certfile = confdir + certfile;
187                         
188                 if(keyfile[0] != '/')
189                         keyfile = confdir + keyfile;
190                         
191                 if(dhfile[0] != '/')
192                         dhfile = confdir + dhfile;
193
194                 /* Load our keys and certificates*/
195                 if(!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str()))
196                 {
197                         ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s", certfile.c_str());
198                 }
199
200                 if(!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))
201                 {
202                         ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read key file %s", keyfile.c_str());
203                 }
204
205                 /* Load the CAs we trust*/
206                 if(!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))
207                 {
208                         ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read CA list from ", cafile.c_str());
209                 }
210
211                 FILE* dhpfile = fopen(dhfile.c_str(), "r");
212                 DH* ret;
213
214                 if(dhpfile == NULL)
215                 {
216                         ServerInstance->Log(DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno));
217                         throw ModuleException();
218                 }
219                 else
220                 {
221                         ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
222                 
223                         if(SSL_CTX_set_tmp_dh(ctx, ret) < 0)
224                         {
225                                 ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters");
226                         }
227                 }
228                 
229                 fclose(dhpfile);
230
231                 DELETE(Conf);
232         }
233
234         virtual ~ModuleSSLOpenSSL()
235         {
236                 SSL_CTX_free(ctx);
237                 delete culllist;
238         }
239         
240         virtual void OnCleanup(int target_type, void* item)
241         {
242                 if(target_type == TYPE_USER)
243                 {
244                         userrec* user = (userrec*)item;
245                         
246                         if(user->GetExt("ssl", dummy) && IS_LOCAL(user) && isin(user->GetPort(), listenports))
247                         {
248                                 // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
249                                 // Potentially there could be multiple SSL modules loaded at once on different ports.
250                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: Adding user %s to cull list", user->nick);
251                                 culllist->AddItem(user, "SSL module unloading");
252                         }
253                         if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports))
254                         {
255                                 ssl_cert* tofree;
256                                 user->GetExt("ssl_cert", tofree);
257                                 delete tofree;
258                                 user->Shrink("ssl_cert");
259                         }
260                 }
261         }
262         
263         virtual void OnUnloadModule(Module* mod, const std::string &name)
264         {
265                 if(mod == this)
266                 {
267                         // We're being unloaded, kill all the users added to the cull list in OnCleanup
268                         int numusers = culllist->Apply();
269                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: Killed %d users for unload of OpenSSL SSL module", numusers);
270                         
271                         for(unsigned int i = 0; i < listenports.size(); i++)
272                                 ServerInstance->Config->DelIOHook(listenports[i]);
273                 }
274         }
275         
276         virtual Version GetVersion()
277         {
278                 return Version(1, 0, 0, 0, VF_VENDOR);
279         }
280
281         void Implements(char* List)
282         {
283                 List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;
284                 List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
285         }
286
287         virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
288         {
289                 issl_session* session = &sessions[fd];
290         
291                 session->fd = fd;
292                 session->inbuf = new char[inbufsize];
293                 session->inbufoffset = 0;               
294                 session->sess = SSL_new(ctx);
295                 session->status = ISSL_NONE;
296         
297                 if(session->sess == NULL)
298                 {
299                         ServerInstance->Log(DEBUG, "m_ssl.so: Couldn't create SSL object: %s", get_error());
300                         return;
301                 }
302                 
303                 if(SSL_set_fd(session->sess, fd) == 0)
304                 {
305                         ServerInstance->Log(DEBUG, "m_ssl.so: Couldn't set fd for SSL object: %s", get_error());
306                         return;
307                 }
308
309                 Handshake(session);
310         }
311
312         virtual void OnRawSocketClose(int fd)
313         {
314                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketClose: %d", fd);
315                 CloseSession(&sessions[fd]);
316         }
317         
318         virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
319         {
320                 issl_session* session = &sessions[fd];
321                 
322                 if(!session->sess)
323                 {
324                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketRead: No session to read from");
325                         readresult = 0;
326                         CloseSession(session);
327                         return 1;
328                 }
329                 
330                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketRead(%d, buffer, %u, %d)", fd, count, readresult);
331                 
332                 if(session->status == ISSL_HANDSHAKING)
333                 {
334                         if(session->rstat == ISSL_READ || session->wstat == ISSL_READ)
335                         {
336                                 // The handshake isn't finished and it wants to read, try to finish it.
337                                 if(Handshake(session))
338                                 {
339                                         // Handshake successfully resumed.
340                                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketRead: successfully resumed handshake");
341                                 }
342                                 else
343                                 {
344                                         // Couldn't resume handshake.   
345                                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketRead: failed to resume handshake");
346                                         return -1;
347                                 }
348                         }
349                         else
350                         {
351                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketRead: handshake wants to write data but we are currently reading");
352                                 return -1;                      
353                         }
354                 }
355                 
356                 // If we resumed the handshake then session->status will be ISSL_OPEN
357                                 
358                 if(session->status == ISSL_OPEN)
359                 {
360                         if(session->wstat == ISSL_READ)
361                         {
362                                 if(DoWrite(session) == 0)
363                                         return 0;
364                         }
365                         
366                         if(session->rstat == ISSL_READ)
367                         {
368                                 int ret = DoRead(session);
369                         
370                                 if(ret > 0)
371                                 {
372                                         if(count <= session->inbufoffset)
373                                         {
374                                                 memcpy(buffer, session->inbuf, count);
375                                                 // Move the stuff left in inbuf to the beginning of it
376                                                 memcpy(session->inbuf, session->inbuf + count, (session->inbufoffset - count));
377                                                 // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp.
378                                                 session->inbufoffset -= count;
379                                                 // Insp uses readresult as the count of how much data there is in buffer, so:
380                                                 readresult = count;
381                                         }
382                                         else
383                                         {
384                                                 // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing.
385                                                 memcpy(buffer, session->inbuf, session->inbufoffset);
386                                                 
387                                                 readresult = session->inbufoffset;
388                                                 // Zero the offset, as there's nothing there..
389                                                 session->inbufoffset = 0;
390                                         }
391                                 
392                                         return 1;
393                                 }
394                                 else
395                                 {
396                                         return ret;
397                                 }
398                         }
399                 }
400                 
401                 return -1;
402         }
403         
404         virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
405         {               
406                 issl_session* session = &sessions[fd];
407
408                 if(!session->sess)
409                 {
410                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketWrite: No session to write to");
411                         CloseSession(session);
412                         return 1;
413                 }
414                 
415                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketWrite: Adding %d bytes to the outgoing buffer", count);                
416                 session->outbuf.append(buffer, count);
417                 
418                 if(session->status == ISSL_HANDSHAKING)
419                 {
420                         // The handshake isn't finished, try to finish it.
421                         if(session->rstat == ISSL_WRITE || session->wstat == ISSL_WRITE)
422                         {
423                                 if(Handshake(session))
424                                 {
425                                         // Handshake successfully resumed.
426                                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketWrite: successfully resumed handshake");
427                                 }
428                                 else
429                                 {
430                                         // Couldn't resume handshake.   
431                                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketWrite: failed to resume handshake"); 
432                                 }
433                         }
434                         else
435                         {
436                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: OnRawSocketWrite: handshake wants to read data but we are currently writing");                    
437                         }
438                 }
439                 
440                 if(session->status == ISSL_OPEN)
441                 {
442                         if(session->rstat == ISSL_WRITE)
443                         {
444                                 DoRead(session);
445                         }
446                         
447                         if(session->wstat == ISSL_WRITE)
448                         {
449                                 return DoWrite(session);
450                         }
451                 }
452                 
453                 return 1;
454         }
455         
456         int DoWrite(issl_session* session)
457         {
458                 int ret = SSL_write(session->sess, session->outbuf.data(), session->outbuf.size());
459                 
460                 if(ret == 0)
461                 {
462                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoWrite: Client closed the connection");
463                         CloseSession(session);
464                         return 0;
465                 }
466                 else if(ret < 0)
467                 {
468                         int err = SSL_get_error(session->sess, ret);
469                         
470                         if(err == SSL_ERROR_WANT_WRITE)
471                         {
472                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoWrite: Not all SSL data written, need to retry: %s", get_error());
473                                 session->wstat = ISSL_WRITE;
474                                 return -1;
475                         }
476                         else if(err == SSL_ERROR_WANT_READ)
477                         {
478                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoWrite: Not all SSL data written but the damn thing wants to read instead: %s", get_error());
479                                 session->wstat = ISSL_READ;
480                                 return -1;
481                         }
482                         else
483                         {
484                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoWrite: Error writing SSL data: %s", get_error());
485                                 CloseSession(session);
486                                 return 0;
487                         }
488                 }
489                 else
490                 {
491                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoWrite: Successfully wrote %d bytes", ret);
492                         session->outbuf = session->outbuf.substr(ret);
493                         return ret;
494                 }
495         }
496         
497         int DoRead(issl_session* session)
498         {
499                 // Is this right? Not sure if the unencrypted data is garaunteed to be the same length.
500                 // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet.
501                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoRead: SSL_read(sess, inbuf+%d, %d-%d)", session->inbufoffset, inbufsize, session->inbufoffset);
502                         
503                 int ret = SSL_read(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);
504
505                 if(ret == 0)
506                 {
507                         // Client closed connection.
508                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoRead: Client closed the connection");
509                         CloseSession(session);
510                         return 0;
511                 }
512                 else if(ret < 0)
513                 {
514                         int err = SSL_get_error(session->sess, ret);
515                                 
516                         if(err == SSL_ERROR_WANT_READ)
517                         {
518                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoRead: Not all SSL data read, need to retry: %s", get_error());
519                                 session->rstat = ISSL_READ;
520                                 return -1;
521                         }
522                         else if(err == SSL_ERROR_WANT_WRITE)
523                         {
524                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoRead: Not all SSL data read but the damn thing wants to write instead: %s", get_error());
525                                 session->rstat = ISSL_WRITE;
526                                 return -1;
527                         }
528                         else
529                         {
530                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoRead: Error reading SSL data: %s", get_error());
531                                 CloseSession(session);
532                                 return 0;
533                         }
534                 }
535                 else
536                 {
537                         // Read successfully 'ret' bytes into inbuf + inbufoffset
538                         // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf'
539                         // 'buffer' is 'count' long
540                         
541                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: DoRead: Read %d bytes, now have %d waiting to be passed up", ret, ret + session->inbufoffset);
542
543                         session->inbufoffset += ret;
544
545                         return ret;
546                 }
547         }
548         
549         // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection
550         virtual void OnWhois(userrec* source, userrec* dest)
551         {
552                 // Bugfix, only send this numeric for *our* SSL users
553                 if(dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) &&  isin(dest->GetPort(), listenports)))
554                 {
555                         source->WriteServ("320 %s %s :is using a secure connection", source->nick, dest->nick);
556                 }
557         }
558         
559         virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname)
560         {
561                 // check if the linking module wants to know about OUR metadata
562                 if(extname == "ssl")
563                 {
564                         // check if this user has an swhois field to send
565                         if(user->GetExt(extname, dummy))
566                         {
567                                 // call this function in the linking module, let it format the data how it
568                                 // sees fit, and send it on its way. We dont need or want to know how.
569                                 proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "ON");
570                         }
571                 }
572         }
573         
574         virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
575         {
576                 // check if its our metadata key, and its associated with a user
577                 if ((target_type == TYPE_USER) && (extname == "ssl"))
578                 {
579                         userrec* dest = (userrec*)target;
580                         // if they dont already have an ssl flag, accept the remote server's
581                         if (!dest->GetExt(extname, dummy))
582                         {
583                                 dest->Extend(extname, "ON");
584                         }
585                 }
586         }
587         
588         bool Handshake(issl_session* session)
589         {               
590                 int ret = SSL_accept(session->sess);
591       
592                 if(ret < 0)
593                 {
594                         int err = SSL_get_error(session->sess, ret);
595                                 
596                         if(err == SSL_ERROR_WANT_READ)
597                         {
598                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: Handshake: Not completed, need to read again: %s", get_error());
599                                 session->rstat = ISSL_READ;
600                                 session->status = ISSL_HANDSHAKING;
601                         }
602                         else if(err == SSL_ERROR_WANT_WRITE)
603                         {
604                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: Handshake: Not completed, need to write more data: %s", get_error());
605                                 session->wstat = ISSL_WRITE;
606                                 session->status = ISSL_HANDSHAKING;
607                                 MakePollWrite(session);
608                         }
609                         else
610                         {
611                                 ServerInstance->Log(DEBUG, "m_ssl_openssl.so: Handshake: Failed, bailing: %s", get_error());
612                                 CloseSession(session);
613                         }
614
615                         return false;
616                 }
617                 else
618                 {
619                         // Handshake complete.
620                         ServerInstance->Log(DEBUG, "m_ssl_openssl.so: Handshake completed");
621                         
622                         // This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater.
623                         userrec* u = ServerInstance->FindDescriptor(session->fd);
624                         if (u)
625                         {
626                                 if (!u->GetExt("ssl", dummy))
627                                         u->Extend("ssl", "ON");
628                         }
629                         
630                         session->status = ISSL_OPEN;
631                         
632                         MakePollWrite(session);
633                         
634                         return true;
635                 }
636         }
637         
638         virtual void OnPostConnect(userrec* user)
639         {
640                 // This occurs AFTER OnUserConnect so we can be sure the
641                 // protocol module has propogated the NICK message.
642                 if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))
643                 {
644                         // Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW.
645                         std::deque<std::string>* metadata = new std::deque<std::string>;
646                         metadata->push_back(user->nick);
647                         metadata->push_back("ssl");             // The metadata id
648                         metadata->push_back("ON");              // The value to send
649                         Event* event = new Event((char*)metadata,(Module*)this,"send_metadata");
650                         event->Send(ServerInstance);            // Trigger the event. We don't care what module picks it up.
651                         DELETE(event);
652                         DELETE(metadata);
653
654                         VerifyCertificate(&sessions[user->GetFd()], user);
655                 }
656         }
657         
658         void MakePollWrite(issl_session* session)
659         {
660                 OnRawSocketWrite(session->fd, NULL, 0);
661         }
662         
663         void CloseSession(issl_session* session)
664         {
665                 if(session->sess)
666                 {
667                         SSL_shutdown(session->sess);
668                         SSL_free(session->sess);
669                 }
670                 
671                 if(session->inbuf)
672                 {
673                         delete[] session->inbuf;
674                 }
675                 
676                 session->outbuf.clear();
677                 session->inbuf = NULL;
678                 session->sess = NULL;
679                 session->status = ISSL_NONE;
680         }
681
682         void VerifyCertificate(issl_session* session, userrec* user)
683         {
684                 X509* cert;
685                 ssl_cert* certinfo = new ssl_cert;
686                 unsigned int n;
687                 unsigned char md[EVP_MAX_MD_SIZE];
688                 const EVP_MD *digest = EVP_md5();
689                 //char* buf;
690
691                 user->Extend("ssl_cert",certinfo);
692
693                 cert = SSL_get_peer_certificate((SSL*)session->sess);
694
695                 if (!cert)
696                 {
697                         certinfo->data.insert(std::make_pair("error","Could not get peer certificate: "+std::string(get_error())));
698                         return;
699                 }
700
701                 /*if (!X509_verify_cert(cert))
702                 {
703                         certinfo->data.insert(std::make_pair("invalid",ConvToStr(1)));
704                 }
705                 else
706                 {
707                         certinfo->data.insert(std::make_pair("invalid",ConvToStr(0)));
708                 }*/
709
710                 //X509_NAME_oneline(nm, 0, 0);
711                 certinfo->data.insert(std::make_pair("dn",std::string(X509_NAME_oneline(X509_get_subject_name(cert),0,0))));
712                 certinfo->data.insert(std::make_pair("issuer",std::string(X509_NAME_oneline(X509_get_issuer_name(cert),0,0))));
713
714                 if (!X509_digest(cert, digest, md, &n))
715                 {
716                         certinfo->data.insert(std::make_pair("error","Out of memory generating fingerprint"));
717                 }
718                 else
719                 {
720                         certinfo->data.insert(std::make_pair("fingerprint",irc::hex(md, n)));
721                 }
722
723                 if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), time(NULL)) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), time(NULL)) == 0))
724                 {
725                         certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate"));
726                 }
727         }
728 };
729
730 class ModuleSSLOpenSSLFactory : public ModuleFactory
731 {
732  public:
733         ModuleSSLOpenSSLFactory()
734         {
735         }
736         
737         ~ModuleSSLOpenSSLFactory()
738         {
739         }
740         
741         virtual Module * CreateModule(InspIRCd* Me)
742         {
743                 return new ModuleSSLOpenSSL(Me);
744         }
745 };
746
747
748 extern "C" void * init_module( void )
749 {
750         return new ModuleSSLOpenSSLFactory;
751 }