00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include <gnutls/gnutls.h>
00016 #include <gnutls/x509.h>
00017 #include "transport.h"
00018 #include "m_cap.h"
00019
00020 #ifdef WINDOWS
00021 #pragma comment(lib, "libgnutls-13.lib")
00022 #endif
00023
00024
00025
00026
00027
00028
00029
00030
00031 enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED };
00032
00033 bool isin(const std::string &host, int port, const std::vector<std::string> &portlist)
00034 {
00035 if (std::find(portlist.begin(), portlist.end(), "*:" + ConvToStr(port)) != portlist.end())
00036 return true;
00037
00038 if (std::find(portlist.begin(), portlist.end(), ":" + ConvToStr(port)) != portlist.end())
00039 return true;
00040
00041 return std::find(portlist.begin(), portlist.end(), host + ":" + ConvToStr(port)) != portlist.end();
00042 }
00043
00046 class issl_session : public classbase
00047 {
00048 public:
00049 issl_session()
00050 {
00051 sess = NULL;
00052 }
00053
00054 gnutls_session_t sess;
00055 issl_status status;
00056 std::string outbuf;
00057 int inbufoffset;
00058 char* inbuf;
00059 int fd;
00060 };
00061
00062 class CommandStartTLS : public Command
00063 {
00064 Module* Caller;
00065 public:
00066
00067 CommandStartTLS (InspIRCd* Instance, Module* mod) : Command(Instance,"STARTTLS", 0, 0, true), Caller(mod)
00068 {
00069 this->source = "m_ssl_gnutls.so";
00070 }
00071
00072 CmdResult Handle (const std::vector<std::string> ¶meters, User *user)
00073 {
00074 if (user->registered == REG_ALL)
00075 {
00076 ServerInstance->Users->QuitUser(user, "STARTTLS not allowed after client registration");
00077 }
00078 else
00079 {
00080 if (!user->GetIOHook())
00081 {
00082 user->WriteNumeric(670, "%s :STARTTLS successful, go ahead with TLS handshake", user->nick.c_str());
00083 user->AddIOHook(Caller);
00084 Caller->OnRawSocketAccept(user->GetFd(), user->GetIPString(), user->GetPort());
00085 }
00086 else
00087 user->WriteNumeric(671, "%s :STARTTLS failure", user->nick.c_str());
00088 }
00089
00090 return CMD_FAILURE;
00091 }
00092 };
00093
00094 class ModuleSSLGnuTLS : public Module
00095 {
00096
00097 ConfigReader* Conf;
00098
00099 char* dummy;
00100
00101 std::vector<std::string> listenports;
00102
00103 int inbufsize;
00104 issl_session* sessions;
00105
00106 gnutls_certificate_credentials x509_cred;
00107 gnutls_dh_params dh_params;
00108
00109 std::string keyfile;
00110 std::string certfile;
00111 std::string cafile;
00112 std::string crlfile;
00113 std::string sslports;
00114 int dh_bits;
00115
00116 int clientactive;
00117 bool cred_alloc;
00118
00119 CommandStartTLS* starttls;
00120
00121 public:
00122
00123 ModuleSSLGnuTLS(InspIRCd* Me)
00124 : Module(Me)
00125 {
00126 ServerInstance->Modules->PublishInterface("BufferedSocketHook", this);
00127
00128 sessions = new issl_session[ServerInstance->SE->GetMaxFds()];
00129
00130
00131 inbufsize = ServerInstance->Config->NetBufferSize;
00132
00133 gnutls_global_init();
00134
00135 cred_alloc = false;
00136
00137 OnRehash(NULL,"ssl");
00138
00139
00140 gnutls_certificate_set_dh_params(x509_cred, dh_params);
00141 Implementation eventlist[] = { I_On005Numeric, I_OnRawSocketConnect, I_OnRawSocketAccept, I_OnRawSocketClose, I_OnRawSocketRead, I_OnRawSocketWrite, I_OnCleanup,
00142 I_OnBufferFlushed, I_OnRequest, I_OnSyncUserMetaData, I_OnDecodeMetaData, I_OnUnloadModule, I_OnRehash, I_OnWhois, I_OnPostConnect, I_OnEvent, I_OnHookUserIO };
00143 ServerInstance->Modules->Attach(eventlist, this, 17);
00144
00145 starttls = new CommandStartTLS(ServerInstance, this);
00146 ServerInstance->AddCommand(starttls);
00147 }
00148
00149 virtual void OnRehash(User* user, const std::string ¶m)
00150 {
00151 Conf = new ConfigReader(ServerInstance);
00152
00153 listenports.clear();
00154 clientactive = 0;
00155 sslports.clear();
00156
00157 for(int index = 0; index < Conf->Enumerate("bind"); index++)
00158 {
00159
00160 std::string x = Conf->ReadValue("bind", "type", index);
00161 if(((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", index) == "gnutls"))
00162 {
00163
00164 std::string port = Conf->ReadValue("bind", "port", index);
00165 std::string addr = Conf->ReadValue("bind", "address", index);
00166
00167 irc::portparser portrange(port, false);
00168 long portno = -1;
00169 while ((portno = portrange.GetToken()))
00170 {
00171 clientactive++;
00172 try
00173 {
00174 listenports.push_back(addr + ":" + ConvToStr(portno));
00175
00176 for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
00177 if ((ServerInstance->Config->ports[i]->GetPort() == portno) && (ServerInstance->Config->ports[i]->GetIP() == addr))
00178 ServerInstance->Config->ports[i]->SetDescription("ssl");
00179 ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %ld", portno);
00180
00181 sslports.append((addr.empty() ? "*" : addr)).append(":").append(ConvToStr(portno)).append(";");
00182 }
00183 catch (ModuleException &e)
00184 {
00185 ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %ld: %s. Maybe it's already hooked by the same port on a different IP, or you have an other SSL or similar module loaded?", portno, e.GetReason());
00186 }
00187 }
00188 }
00189 }
00190
00191 if (!sslports.empty())
00192 sslports.erase(sslports.end() - 1);
00193
00194 if(param != "ssl")
00195 {
00196 delete Conf;
00197 return;
00198 }
00199
00200 std::string confdir(ServerInstance->ConfigFileName);
00201
00202 confdir = confdir.substr(0, confdir.find_last_of('/') + 1);
00203
00204 cafile = Conf->ReadValue("gnutls", "cafile", 0);
00205 crlfile = Conf->ReadValue("gnutls", "crlfile", 0);
00206 certfile = Conf->ReadValue("gnutls", "certfile", 0);
00207 keyfile = Conf->ReadValue("gnutls", "keyfile", 0);
00208 dh_bits = Conf->ReadInteger("gnutls", "dhbits", 0, false);
00209
00210
00211 if (cafile.empty())
00212 cafile = "ca.pem";
00213
00214 if (crlfile.empty())
00215 crlfile = "crl.pem";
00216
00217 if (certfile.empty())
00218 certfile = "cert.pem";
00219
00220 if (keyfile.empty())
00221 keyfile = "key.pem";
00222
00223 if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096))
00224 dh_bits = 1024;
00225
00226
00227 if ((cafile[0] != '/') && (!ServerInstance->Config->StartsWithWindowsDriveLetter(cafile)))
00228 cafile = confdir + cafile;
00229
00230 if ((crlfile[0] != '/') && (!ServerInstance->Config->StartsWithWindowsDriveLetter(crlfile)))
00231 crlfile = confdir + crlfile;
00232
00233 if ((certfile[0] != '/') && (!ServerInstance->Config->StartsWithWindowsDriveLetter(certfile)))
00234 certfile = confdir + certfile;
00235
00236 if ((keyfile[0] != '/') && (!ServerInstance->Config->StartsWithWindowsDriveLetter(keyfile)))
00237 keyfile = confdir + keyfile;
00238
00239 int ret;
00240
00241 if (cred_alloc)
00242 {
00243
00244 gnutls_dh_params_deinit(dh_params);
00245 gnutls_certificate_free_credentials(x509_cred);
00246 }
00247 else
00248 cred_alloc = true;
00249
00250 if((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0)
00251 ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to allocate certificate credentials: %s", gnutls_strerror(ret));
00252
00253 if((ret = gnutls_dh_params_init(&dh_params)) < 0)
00254 ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret));
00255
00256 if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
00257 ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret));
00258
00259 if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
00260 ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret));
00261
00262 if((ret = gnutls_certificate_set_x509_key_file (x509_cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
00263 {
00264
00265 throw ModuleException("Unable to load GnuTLS server certificate: " + std::string(gnutls_strerror(ret)));
00266 }
00267
00268
00269 GenerateDHParams();
00270
00271 delete Conf;
00272 }
00273
00274 void GenerateDHParams()
00275 {
00276
00277
00278
00279
00280
00281 int ret;
00282
00283 if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0)
00284 ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret));
00285 }
00286
00287 virtual ~ModuleSSLGnuTLS()
00288 {
00289 gnutls_dh_params_deinit(dh_params);
00290 gnutls_certificate_free_credentials(x509_cred);
00291 gnutls_global_deinit();
00292 ServerInstance->Modules->UnpublishInterface("BufferedSocketHook", this);
00293 delete[] sessions;
00294 }
00295
00296 virtual void OnCleanup(int target_type, void* item)
00297 {
00298 if(target_type == TYPE_USER)
00299 {
00300 User* user = (User*)item;
00301
00302 if (user->GetIOHook() == this)
00303 {
00304
00305
00306 ServerInstance->Users->QuitUser(user, "SSL module unloading");
00307 user->DelIOHook();
00308 }
00309 if (user->GetExt("ssl_cert", dummy))
00310 {
00311 ssl_cert* tofree;
00312 user->GetExt("ssl_cert", tofree);
00313 delete tofree;
00314 user->Shrink("ssl_cert");
00315 }
00316 }
00317 }
00318
00319 virtual void OnUnloadModule(Module* mod, const std::string &name)
00320 {
00321 if(mod == this)
00322 {
00323 for(unsigned int i = 0; i < listenports.size(); i++)
00324 {
00325 for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
00326 if (listenports[i] == (ServerInstance->Config->ports[j]->GetIP()+":"+ConvToStr(ServerInstance->Config->ports[j]->GetPort())))
00327 ServerInstance->Config->ports[j]->SetDescription("plaintext");
00328 }
00329 }
00330 }
00331
00332 virtual Version GetVersion()
00333 {
00334 return Version("$Id: m_ssl_gnutls.cpp 10621 2008-10-04 21:18:26Z brain $", VF_VENDOR, API_VERSION);
00335 }
00336
00337
00338 virtual void On005Numeric(std::string &output)
00339 {
00340 output.append(" SSL=" + sslports);
00341 }
00342
00343 virtual void OnHookUserIO(User* user, const std::string &targetip)
00344 {
00345 if (!user->GetIOHook() && isin(targetip,user->GetPort(),listenports))
00346 {
00347
00348 user->AddIOHook(this);
00349 }
00350 }
00351
00352 virtual const char* OnRequest(Request* request)
00353 {
00354 ISHRequest* ISR = (ISHRequest*)request;
00355 if (strcmp("IS_NAME", request->GetId()) == 0)
00356 {
00357 return "gnutls";
00358 }
00359 else if (strcmp("IS_HOOK", request->GetId()) == 0)
00360 {
00361 const char* ret = "OK";
00362 try
00363 {
00364 ret = ISR->Sock->AddIOHook((Module*)this) ? "OK" : NULL;
00365 }
00366 catch (ModuleException &e)
00367 {
00368 return NULL;
00369 }
00370 return ret;
00371 }
00372 else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
00373 {
00374 return ISR->Sock->DelIOHook() ? "OK" : NULL;
00375 }
00376 else if (strcmp("IS_HSDONE", request->GetId()) == 0)
00377 {
00378 if (ISR->Sock->GetFd() < 0)
00379 return "OK";
00380
00381 issl_session* session = &sessions[ISR->Sock->GetFd()];
00382 return (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) ? NULL : "OK";
00383 }
00384 else if (strcmp("IS_ATTACH", request->GetId()) == 0)
00385 {
00386 if (ISR->Sock->GetFd() > -1)
00387 {
00388 issl_session* session = &sessions[ISR->Sock->GetFd()];
00389 if (session->sess)
00390 {
00391 if ((Extensible*)ServerInstance->FindDescriptor(ISR->Sock->GetFd()) == (Extensible*)(ISR->Sock))
00392 {
00393 VerifyCertificate(session, (BufferedSocket*)ISR->Sock);
00394 return "OK";
00395 }
00396 }
00397 }
00398 }
00399 return NULL;
00400 }
00401
00402
00403 virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
00404 {
00405
00406 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
00407 return;
00408
00409 issl_session* session = &sessions[fd];
00410
00411
00412 if (session->sess)
00413 return;
00414
00415 session->fd = fd;
00416 session->inbuf = new char[inbufsize];
00417 session->inbufoffset = 0;
00418
00419 gnutls_init(&session->sess, GNUTLS_SERVER);
00420
00421 gnutls_set_default_priority(session->sess);
00422 gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
00423 gnutls_dh_set_prime_bits(session->sess, dh_bits);
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd);
00434
00435 gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST);
00436
00437 Handshake(session);
00438 }
00439
00440 virtual void OnRawSocketConnect(int fd)
00441 {
00442
00443 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
00444 return;
00445
00446 issl_session* session = &sessions[fd];
00447
00448 session->fd = fd;
00449 session->inbuf = new char[inbufsize];
00450 session->inbufoffset = 0;
00451
00452 gnutls_init(&session->sess, GNUTLS_CLIENT);
00453
00454 gnutls_set_default_priority(session->sess);
00455 gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
00456 gnutls_dh_set_prime_bits(session->sess, dh_bits);
00457 gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd);
00458
00459 Handshake(session);
00460 }
00461
00462 virtual void OnRawSocketClose(int fd)
00463 {
00464
00465 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds()))
00466 return;
00467
00468 CloseSession(&sessions[fd]);
00469
00470 EventHandler* user = ServerInstance->SE->GetRef(fd);
00471
00472 if ((user) && (user->GetExt("ssl_cert", dummy)))
00473 {
00474 ssl_cert* tofree;
00475 user->GetExt("ssl_cert", tofree);
00476 delete tofree;
00477 user->Shrink("ssl_cert");
00478 }
00479 }
00480
00481 virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
00482 {
00483
00484 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
00485 return 0;
00486
00487 issl_session* session = &sessions[fd];
00488
00489 if (!session->sess)
00490 {
00491 readresult = 0;
00492 CloseSession(session);
00493 return 1;
00494 }
00495
00496 if (session->status == ISSL_HANDSHAKING_READ)
00497 {
00498
00499
00500 if(!Handshake(session))
00501 {
00502
00503 return -1;
00504 }
00505 }
00506 else if (session->status == ISSL_HANDSHAKING_WRITE)
00507 {
00508 errno = EAGAIN;
00509 MakePollWrite(session);
00510 return -1;
00511 }
00512
00513
00514
00515 if (session->status == ISSL_HANDSHAKEN)
00516 {
00517
00518
00519 int ret = gnutls_record_recv(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);
00520
00521 if (ret == 0)
00522 {
00523
00524 readresult = 0;
00525 CloseSession(session);
00526 return 1;
00527 }
00528 else if (ret < 0)
00529 {
00530 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
00531 {
00532 errno = EAGAIN;
00533 return -1;
00534 }
00535 else
00536 {
00537 readresult = 0;
00538 CloseSession(session);
00539 }
00540 }
00541 else
00542 {
00543
00544
00545
00546
00547 unsigned int length = ret + session->inbufoffset;
00548
00549 if(count <= length)
00550 {
00551 memcpy(buffer, session->inbuf, count);
00552
00553 memmove(session->inbuf, session->inbuf + count, (length - count));
00554
00555 session->inbufoffset = length - count;
00556
00557 readresult = count;
00558 }
00559 else
00560 {
00561
00562 memcpy(buffer, session->inbuf, length);
00563
00564 session->inbufoffset = 0;
00565
00566 readresult = length;
00567 }
00568 }
00569 }
00570 else if(session->status == ISSL_CLOSING)
00571 readresult = 0;
00572
00573 return 1;
00574 }
00575
00576 virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
00577 {
00578
00579 if ((fd < 0) || (fd > ServerInstance->SE->GetMaxFds() - 1))
00580 return 0;
00581
00582 issl_session* session = &sessions[fd];
00583 const char* sendbuffer = buffer;
00584
00585 if (!session->sess)
00586 {
00587 CloseSession(session);
00588 return 1;
00589 }
00590
00591 session->outbuf.append(sendbuffer, count);
00592 sendbuffer = session->outbuf.c_str();
00593 count = session->outbuf.size();
00594
00595 if (session->status == ISSL_HANDSHAKING_WRITE)
00596 {
00597
00598 Handshake(session);
00599 errno = EAGAIN;
00600 return -1;
00601 }
00602
00603 int ret = 0;
00604
00605 if (session->status == ISSL_HANDSHAKEN)
00606 {
00607 ret = gnutls_record_send(session->sess, sendbuffer, count);
00608
00609 if (ret == 0)
00610 {
00611 CloseSession(session);
00612 }
00613 else if (ret < 0)
00614 {
00615 if(ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED)
00616 {
00617 CloseSession(session);
00618 }
00619 else
00620 {
00621 errno = EAGAIN;
00622 }
00623 }
00624 else
00625 {
00626 session->outbuf = session->outbuf.substr(ret);
00627 }
00628 }
00629
00630 MakePollWrite(session);
00631
00632
00633
00634
00635 return ret < 1 ? 0 : ret;
00636 }
00637
00638
00639 virtual void OnWhois(User* source, User* dest)
00640 {
00641 if (!clientactive)
00642 return;
00643
00644
00645 if (dest->GetExt("ssl", dummy) || ((IS_LOCAL(dest) && (dest->GetIOHook() == this))))
00646 {
00647 ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick.c_str(), dest->nick.c_str());
00648 }
00649 }
00650
00651 virtual void OnSyncUserMetaData(User* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
00652 {
00653
00654 if(extname == "ssl")
00655 {
00656
00657 if(user->GetExt(extname, dummy))
00658 {
00659
00660
00661 proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");
00662 }
00663 }
00664 }
00665
00666 virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
00667 {
00668
00669 if ((target_type == TYPE_USER) && (extname == "ssl"))
00670 {
00671 User* dest = (User*)target;
00672
00673 if (!dest->GetExt(extname, dummy))
00674 {
00675 dest->Extend(extname, "ON");
00676 }
00677 }
00678 }
00679
00680 bool Handshake(issl_session* session)
00681 {
00682 int ret = gnutls_handshake(session->sess);
00683
00684 if (ret < 0)
00685 {
00686 if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
00687 {
00688
00689
00690 if(gnutls_record_get_direction(session->sess) == 0)
00691 {
00692
00693 session->status = ISSL_HANDSHAKING_READ;
00694 }
00695 else
00696 {
00697
00698 session->status = ISSL_HANDSHAKING_WRITE;
00699 MakePollWrite(session);
00700 }
00701 }
00702 else
00703 {
00704
00705 CloseSession(session);
00706 session->status = ISSL_CLOSING;
00707 }
00708
00709 return false;
00710 }
00711 else
00712 {
00713
00714
00715 User* extendme = ServerInstance->FindDescriptor(session->fd);
00716 if (extendme)
00717 {
00718 if (!extendme->GetExt("ssl", dummy))
00719 extendme->Extend("ssl", "ON");
00720 }
00721
00722
00723 session->status = ISSL_HANDSHAKEN;
00724
00725
00726 MakePollWrite(session);
00727
00728 return true;
00729 }
00730 }
00731
00732 virtual void OnPostConnect(User* user)
00733 {
00734
00735
00736 if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))
00737 {
00738
00739 ServerInstance->PI->SendMetaData(user, TYPE_USER, "SSL", "on");
00740
00741 VerifyCertificate(&sessions[user->GetFd()],user);
00742 if (sessions[user->GetFd()].sess)
00743 {
00744 std::string cipher = gnutls_kx_get_name(gnutls_kx_get(sessions[user->GetFd()].sess));
00745 cipher.append("-").append(gnutls_cipher_get_name(gnutls_cipher_get(sessions[user->GetFd()].sess))).append("-");
00746 cipher.append(gnutls_mac_get_name(gnutls_mac_get(sessions[user->GetFd()].sess)));
00747 user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), cipher.c_str());
00748 }
00749 }
00750 }
00751
00752 void MakePollWrite(issl_session* session)
00753 {
00754
00755 EventHandler* eh = ServerInstance->FindDescriptor(session->fd);
00756 if (eh)
00757 ServerInstance->SE->WantWrite(eh);
00758 }
00759
00760 virtual void OnBufferFlushed(User* user)
00761 {
00762 if (user->GetExt("ssl"))
00763 {
00764 issl_session* session = &sessions[user->GetFd()];
00765 if (session && session->outbuf.size())
00766 OnRawSocketWrite(user->GetFd(), NULL, 0);
00767 }
00768 }
00769
00770 void CloseSession(issl_session* session)
00771 {
00772 if(session->sess)
00773 {
00774 gnutls_bye(session->sess, GNUTLS_SHUT_WR);
00775 gnutls_deinit(session->sess);
00776 }
00777
00778 if(session->inbuf)
00779 {
00780 delete[] session->inbuf;
00781 }
00782
00783 session->outbuf.clear();
00784 session->inbuf = NULL;
00785 session->sess = NULL;
00786 session->status = ISSL_NONE;
00787 }
00788
00789 void VerifyCertificate(issl_session* session, Extensible* user)
00790 {
00791 if (!session->sess || !user)
00792 return;
00793
00794 unsigned int status;
00795 const gnutls_datum_t* cert_list;
00796 int ret;
00797 unsigned int cert_list_size;
00798 gnutls_x509_crt_t cert;
00799 char name[MAXBUF];
00800 unsigned char digest[MAXBUF];
00801 size_t digest_size = sizeof(digest);
00802 size_t name_size = sizeof(name);
00803 ssl_cert* certinfo = new ssl_cert;
00804
00805 user->Extend("ssl_cert",certinfo);
00806
00807
00808
00809
00810 ret = gnutls_certificate_verify_peers2(session->sess, &status);
00811
00812 if (ret < 0)
00813 {
00814 certinfo->data.insert(std::make_pair("error",std::string(gnutls_strerror(ret))));
00815 return;
00816 }
00817
00818 if (status & GNUTLS_CERT_INVALID)
00819 {
00820 certinfo->data.insert(std::make_pair("invalid",ConvToStr(1)));
00821 }
00822 else
00823 {
00824 certinfo->data.insert(std::make_pair("invalid",ConvToStr(0)));
00825 }
00826 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
00827 {
00828 certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1)));
00829 }
00830 else
00831 {
00832 certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0)));
00833 }
00834 if (status & GNUTLS_CERT_REVOKED)
00835 {
00836 certinfo->data.insert(std::make_pair("revoked",ConvToStr(1)));
00837 }
00838 else
00839 {
00840 certinfo->data.insert(std::make_pair("revoked",ConvToStr(0)));
00841 }
00842 if (status & GNUTLS_CERT_SIGNER_NOT_CA)
00843 {
00844 certinfo->data.insert(std::make_pair("trusted",ConvToStr(0)));
00845 }
00846 else
00847 {
00848 certinfo->data.insert(std::make_pair("trusted",ConvToStr(1)));
00849 }
00850
00851
00852
00853
00854
00855 if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509)
00856 {
00857 certinfo->data.insert(std::make_pair("error","No X509 keys sent"));
00858 return;
00859 }
00860
00861 ret = gnutls_x509_crt_init(&cert);
00862 if (ret < 0)
00863 {
00864 certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
00865 return;
00866 }
00867
00868 cert_list_size = 0;
00869 cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size);
00870 if (cert_list == NULL)
00871 {
00872 certinfo->data.insert(std::make_pair("error","No certificate was found"));
00873 return;
00874 }
00875
00876
00877
00878
00879
00880 ret = gnutls_x509_crt_import(cert, &am