Anope IRC Services  Version 2.0
m_ssl_openssl.cpp
Go to the documentation of this file.
1 /* RequiredLibraries: ssl,crypto */
2 /* RequiredWindowsLibraries: ssleay32,libeay32 */
3 
4 #include "module.h"
5 #include "modules/ssl.h"
6 
7 #define OPENSSL_NO_SHA512
8 #include <openssl/bio.h>
9 #include <openssl/ssl.h>
10 #include <openssl/err.h>
11 #include <openssl/crypto.h>
12 #include <openssl/evp.h>
13 
14 static SSL_CTX *server_ctx, *client_ctx;
15 
16 class MySSLService : public SSLService
17 {
18  public:
19  MySSLService(Module *o, const Anope::string &n);
20 
24  void Init(Socket *s) anope_override;
25 };
26 
27 class SSLSocketIO : public SocketIO
28 {
29  public:
30  /* The SSL socket for this socket */
31  SSL *sslsock;
32 
35  SSLSocketIO();
36 
43  int Recv(Socket *s, char *buf, size_t sz) anope_override;
44 
50  int Send(Socket *s, const char *buf, size_t sz) anope_override;
51 
57 
63 
69  void Connect(ConnectionSocket *s, const Anope::string &target, int port) anope_override;
70 
76 
79  void Destroy() anope_override;
80 };
81 
82 class SSLModule;
83 static SSLModule *me;
84 class SSLModule : public Module
85 {
87 
88  public:
90 
91  SSLModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), service(this, "ssl")
92  {
93  me = this;
94 
95  this->SetPermanent(true);
96 
97  SSL_library_init();
98  SSL_load_error_strings();
99 
100  client_ctx = SSL_CTX_new(SSLv23_client_method());
101  server_ctx = SSL_CTX_new(SSLv23_server_method());
102 
103  if (!client_ctx || !server_ctx)
104  throw ModuleException("Error initializing SSL CTX");
105 
106  SSL_CTX_set_mode(client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
107  SSL_CTX_set_mode(server_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
108 
109  Anope::string context_name = "Anope";
110  SSL_CTX_set_session_id_context(client_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
111  SSL_CTX_set_session_id_context(server_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
112  }
113 
115  {
116  for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
117  {
118  Socket *s = it->second;
119  ++it;
120 
121  if (dynamic_cast<SSLSocketIO *>(s->io))
122  delete s;
123  }
124 
125  SSL_CTX_free(client_ctx);
126  SSL_CTX_free(server_ctx);
127  }
128 
129  void OnReload(Configuration::Conf *conf) anope_override
130  {
131  Configuration::Block *config = conf->GetModule(this);
132 
133  this->certfile = config->Get<const Anope::string>("cert", "data/anope.crt");
134  this->keyfile = config->Get<const Anope::string>("key", "data/anope.key");
135 
136  if (Anope::IsFile(this->certfile.c_str()))
137  {
138  if (!SSL_CTX_use_certificate_file(client_ctx, this->certfile.c_str(), SSL_FILETYPE_PEM) || !SSL_CTX_use_certificate_file(server_ctx, this->certfile.c_str(), SSL_FILETYPE_PEM))
139  throw ConfigException("Error loading certificate");
140  else
141  Log(LOG_DEBUG) << "m_ssl_openssl: Successfully loaded certificate " << this->certfile;
142  }
143  else
144  Log() << "Unable to open certificate " << this->certfile;
145 
146  if (Anope::IsFile(this->keyfile.c_str()))
147  {
148  if (!SSL_CTX_use_PrivateKey_file(client_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(server_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM))
149  throw ConfigException("Error loading private key");
150  else
151  Log(LOG_DEBUG) << "m_ssl_openssl: Successfully loaded private key " << this->keyfile;
152  }
153  else
154  {
155  if (Anope::IsFile(this->certfile.c_str()))
156  throw ConfigException("Error loading private key " + this->keyfile + " - file not found");
157  else
158  Log() << "Unable to open private key " << this->keyfile;
159  }
160 
161  }
162 
163  void OnPreServerConnect() anope_override
164  {
165  Configuration::Block *config = Config->GetBlock("uplink", Anope::CurrentUplink);
166 
167  if (config->Get<bool>("ssl"))
168  {
169  this->service.Init(UplinkSock);
170  }
171  }
172 };
173 
175 {
176 }
177 
178 void MySSLService::Init(Socket *s)
179 {
180  if (s->io != &NormalSocketIO)
181  throw CoreException("Socket initializing SSL twice");
182 
183  s->io = new SSLSocketIO();
184 }
185 
187 {
188  this->sslsock = NULL;
189 }
190 
191 int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
192 {
193  int i = SSL_read(this->sslsock, buf, sz);
194  if (i > 0)
195  TotalRead += i;
196  else if (i < 0)
197  {
198  int err = SSL_get_error(this->sslsock, i);
199  switch (err)
200  {
201  case SSL_ERROR_WANT_READ:
202  case SSL_ERROR_WANT_WRITE:
204  }
205  }
206 
207  return i;
208 }
209 
210 int SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
211 {
212  int i = SSL_write(this->sslsock, buf, sz);
213  if (i > 0)
214  TotalWritten += i;
215  else if (i < 0)
216  {
217  int err = SSL_get_error(this->sslsock, i);
218  switch (err)
219  {
220  case SSL_ERROR_WANT_READ:
221  case SSL_ERROR_WANT_WRITE:
223  }
224  }
225  return i;
226 }
227 
229 {
230  if (s->io == &NormalSocketIO)
231  throw SocketException("Attempting to accept on uninitialized socket with SSL");
232 
233  sockaddrs conaddr;
234 
235  socklen_t size = sizeof(conaddr);
236  int newsock = accept(s->GetFD(), &conaddr.sa, &size);
237 
238 #ifndef INVALID_SOCKET
239  const int INVALID_SOCKET = -1;
240 #endif
241 
242  if (newsock < 0 || newsock == INVALID_SOCKET)
243  throw SocketException("Unable to accept connection: " + Anope::LastError());
244 
245  ClientSocket *newsocket = s->OnAccept(newsock, conaddr);
246  me->service.Init(newsocket);
248 
249  io->sslsock = SSL_new(server_ctx);
250  if (!io->sslsock)
251  throw SocketException("Unable to initialize SSL socket");
252 
253  SSL_set_accept_state(io->sslsock);
254 
255  if (!SSL_set_fd(io->sslsock, newsocket->GetFD()))
256  throw SocketException("Unable to set SSL fd");
257 
258  newsocket->flags[SF_ACCEPTING] = true;
259  this->FinishAccept(newsocket);
260 
261  return newsocket;
262 }
263 
265 {
266  if (cs->io == &NormalSocketIO)
267  throw SocketException("Attempting to finish connect uninitialized socket with SSL");
268  else if (cs->flags[SF_ACCEPTED])
269  return SF_ACCEPTED;
270  else if (!cs->flags[SF_ACCEPTING])
271  throw SocketException("SSLSocketIO::FinishAccept called for a socket not accepted nor accepting?");
272 
274 
275  int ret = SSL_accept(io->sslsock);
276  if (ret <= 0)
277  {
278  int error = SSL_get_error(io->sslsock, ret);
279  if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE))
280  {
281  SocketEngine::Change(cs, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE);
282  SocketEngine::Change(cs, error == SSL_ERROR_WANT_READ, SF_READABLE);
283  return SF_ACCEPTING;
284  }
285  else
286  {
287  cs->OnError(ERR_error_string(ERR_get_error(), NULL));
288  cs->flags[SF_DEAD] = true;
289  cs->flags[SF_ACCEPTING] = false;
290  return SF_DEAD;
291  }
292  }
293  else
294  {
295  cs->flags[SF_ACCEPTED] = true;
296  cs->flags[SF_ACCEPTING] = false;
297  SocketEngine::Change(cs, false, SF_WRITABLE);
299  cs->OnAccept();
300  return SF_ACCEPTED;
301  }
302 }
303 
304 void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port)
305 {
306  if (s->io == &NormalSocketIO)
307  throw SocketException("Attempting to connect uninitialized socket with SSL");
308 
309  s->flags[SF_CONNECTING] = s->flags[SF_CONNECTED] = false;
310 
311  s->conaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, target, port);
312  int c = connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size());
313  if (c == -1)
314  {
315  if (Anope::LastErrorCode() != EINPROGRESS)
316  {
318  s->flags[SF_DEAD] = true;
319  return;
320  }
321  else
322  {
324  s->flags[SF_CONNECTING] = true;
325  return;
326  }
327  }
328  else
329  {
330  s->flags[SF_CONNECTING] = true;
331  this->FinishConnect(s);
332  }
333 }
334 
336 {
337  if (s->io == &NormalSocketIO)
338  throw SocketException("Attempting to finish connect uninitialized socket with SSL");
339  else if (s->flags[SF_CONNECTED])
340  return SF_CONNECTED;
341  else if (!s->flags[SF_CONNECTING])
342  throw SocketException("SSLSocketIO::FinishConnect called for a socket not connected nor connecting?");
343 
345 
346  if (io->sslsock == NULL)
347  {
348  io->sslsock = SSL_new(client_ctx);
349  if (!io->sslsock)
350  throw SocketException("Unable to initialize SSL socket");
351 
352  if (!SSL_set_fd(io->sslsock, s->GetFD()))
353  throw SocketException("Unable to set SSL fd");
354  }
355 
356  int ret = SSL_connect(io->sslsock);
357  if (ret <= 0)
358  {
359  int error = SSL_get_error(io->sslsock, ret);
360  if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE))
361  {
362  SocketEngine::Change(s, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE);
363  SocketEngine::Change(s, error == SSL_ERROR_WANT_READ, SF_READABLE);
364  return SF_CONNECTING;
365  }
366  else
367  {
368  s->OnError(ERR_error_string(ERR_get_error(), NULL));
369  s->flags[SF_CONNECTING] = false;
370  s->flags[SF_DEAD] = true;
371  return SF_DEAD;
372  }
373  }
374  else
375  {
376  s->flags[SF_CONNECTING] = false;
377  s->flags[SF_CONNECTED] = true;
380  s->OnConnect();
381  return SF_CONNECTED;
382  }
383 }
384 
386 {
387  if (this->sslsock)
388  {
389  SSL_shutdown(this->sslsock);
390  SSL_free(this->sslsock);
391  }
392 
393  delete this;
394 }
395 
int Send(Socket *s, const char *buf, size_t sz) anope_override
void pton(int type, const Anope::string &address, int pport=0)
Definition: sockets.cpp:121
std::bitset< SF_SIZE > flags
Definition: sockets.h:203
size_t size() const
Definition: sockets.cpp:43
SocketIO * io
Definition: sockets.h:209
virtual ClientSocket * OnAccept(int fd, const sockaddrs &addr)=0
SocketFlag
Definition: sockets.h:124
sockaddr sa
Definition: sockets.h:30
CoreExport SocketIO NormalSocketIO
Definition: sockets.cpp:29
virtual void OnConnect()
CoreExport const string LastError()
Definition: misc.cpp:606
CoreExport bool IsFile(const Anope::string &file)
Definition: misc.cpp:266
bool IsIPv6() const
Definition: sockets.cpp:479
static std::map< int, Socket * > Sockets
Definition: socketengine.h:24
CoreExport int LastErrorCode()
Definition: misc.cpp:597
static void Change(Socket *s, bool set, SocketFlag flag)
virtual void OnError(const Anope::string &error)
void Connect(ConnectionSocket *s, const Anope::string &target, int port) anope_override
int GetFD() const
Definition: sockets.cpp:474
Anope::string keyfile
size_type length() const
Definition: anope.h:131
sockaddrs conaddr
Definition: sockets.h:391
Definition: Config.cs:26
int Recv(Socket *s, char *buf, size_t sz) anope_override
MySSLService(Module *o, const Anope::string &n)
ClientSocket * Accept(ListenSocket *s) anope_override
SSLModule(const Anope::string &modname, const Anope::string &creator)
static SSL_CTX * client_ctx
static void SetLastError(int)
Definition: sockets.cpp:557
void Init(Socket *s) anope_override
#define anope_override
Definition: services.h:56
#define MODULE_INIT(x)
Definition: modules.h:45
virtual void OnError(const Anope::string &error)
MySSLService service
CoreExport int CurrentUplink
Definition: main.cpp:43
CoreExport uint32_t TotalWritten
Definition: sockets.cpp:27
void OnReload(Configuration::Conf *conf) anope_override
static SSLModule * me
SocketFlag FinishAccept(ClientSocket *cs) anope_override
CoreExport uint32_t TotalRead
Definition: sockets.cpp:26
static SSL_CTX * server_ctx
T anope_dynamic_static_cast(O ptr)
Definition: anope.h:774
void Destroy() anope_override
void OnPreServerConnect() anope_override
SocketFlag FinishConnect(ConnectionSocket *s) anope_override
virtual void OnAccept()
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
T Get(const Anope::string &tag)
Definition: config.h:44
#define accept
Definition: socket.h:28
Definition: ssl.h:2
Definition: modules.h:163