added gnutls backend and moved backend code into new files
[ircu2.10.12-pk.git] / ircd / ssl.openssl.c
1 /*
2  * IRC - Internet Relay Chat, ircd/ssl.openssl.c
3  * Copyright (C) 2015 pk910 (Philipp Kreil)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 1, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /** @file
20  * @brief Implementation of functions for handling ssl connections
21  * @version $Id$
22  */
23
24 static struct SSLPendingConections {
25   struct SSLConnection *connection;
26   struct SSLPendingConections *next;
27   
28   void *data;
29   enum SSLDataType datatype;
30 };
31
32 struct SSLPendingConections *firstPendingConection = NULL;
33 int ssl_is_initialized = 0;
34
35 static void ssl_init() {
36   if(ssl_is_initialized)
37     return;
38   ssl_is_initialized = 1;
39         SSL_library_init();
40         OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
41         SSL_load_error_strings();
42 }
43
44 void ssl_free_connection(struct SSLConnection *connection) {
45   SSL_CTX *context = NULL;
46   if(FlagHas(&connection->flags, SSLFLAG_OUTGOING)) {
47     struct SSLOutConnection *outconn = (struct SSLOutConnection *)connection;
48     context = outconn->context;
49   }
50   SSL_shutdown(connection->session);
51   SSL_free(connection->session);
52   if(context)
53     SSL_CTX_free(context);
54   free(connection);
55 }
56
57 void ssl_free_listener(struct SSLListener *listener) {
58   SSL_CTX_free(listener->context);
59   free(listener);
60 }
61
62 static void ssl_handshake_completed(struct SSLConnection *connection, int success) {
63   struct SSLPendingConections *pending, *lastPending = NULL;
64   for(pending = firstPendingConection; pending; pending = pending->next) {
65     if(pending->connection == connection) {
66       if(lastPending)
67         lastPending->next = pending->next;
68       else
69         firstPendingConection = pending->next;
70       switch(pending->datatype) {
71         case SSLData_Client: {
72             struct Client *cptr = (struct Client *) pending->data;
73             if(success) {
74               if(FlagHas(&connection->flags, SSLFLAG_INCOMING))
75                 start_auth(cptr);
76               else if(!completed_connection(cptr))
77                 exit_client_msg(cptr, cptr, &me, "Registration failed.");
78             } else
79               exit_client_msg(cptr, cptr, &me, "SSL Handshake failed.");
80           }
81           break;
82       }
83       free(pending);
84     }
85     lastPending = pending;
86   }
87 }
88
89 static int ssl_handshake_outgoing(struct SSLConnection *connection) {
90   int ret = SSL_do_handshake(connection->session);
91   FlagClr(&connection->flags, SSLFLAG_HANDSHAKE_R);
92   FlagClr(&connection->flags, SSLFLAG_HANDSHAKE_W);
93   
94         switch(SSL_get_error(connection->session, ret)) {
95                 case SSL_ERROR_NONE:
96                         FlagClr(&connection->flags, SSLFLAG_HANDSHAKE);
97       FlagSet(&connection->flags, SSLFLAG_READY);
98       
99       ssl_handshake_completed(connection, 1);
100                         break;
101                 case SSL_ERROR_WANT_READ:
102                         FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
103                         break;
104                 case SSL_ERROR_WANT_WRITE:
105                         FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
106                         break;
107                 default:
108                         
109                         break;
110         }
111 }
112
113 struct SSLConnection *ssl_create_connect(int fd, void *data, enum SSLDataType datatype) {
114   struct SSLOutConnection *connection = malloc(sizeof(*connection));
115   struct SSLConnection *sslconn = (struct SSLConnection *)connection;
116   struct SSLPendingConections *pending = NULL;
117   
118   if(!connection)
119     return NULL;
120   
121   if(!ssl_is_initialized)
122     ssl_init();
123   
124   connection->context = SSL_CTX_new(SSLv23_client_method());
125         if(!connection->context) {
126                 goto ssl_create_connect_failed;
127         }
128         connection->session = SSL_new(connection->context);
129         if(!connection->session) {
130                 goto ssl_create_connect_failed;
131         }
132         if(!SSL_set_fd(connection->session, fd)) {
133                 goto ssl_create_connect_failed;
134         }
135         SSL_set_connect_state(connection->session);
136         FlagSet(&connection->flags, SSLFLAG_OUTGOING);
137   FlagSet(&connection->flags, SSLFLAG_HANDSHAKE);
138   
139   pending = malloc(sizeof(*pending));
140   if(!pending) {
141     goto ssl_create_connect_failed;
142   }
143   pending->connection = connection;
144   pending->next = firstPendingConection;
145   firstPendingConection = pending;
146   
147   pending->data = data;
148   pending->datatype = datatype;
149   
150         return sslconn;
151 ssl_create_connect_failed:
152         free(connection);
153         return NULL;
154 }
155
156 void ssl_start_handshake_connect(struct SSLConnection *connection) {
157   ssl_handshake_outgoing(connection);
158 }
159
160 struct SSLListener *ssl_create_listener() {
161   if(!ssl_is_initialized)
162     ssl_init();
163   
164   struct SSLListener *listener = calloc(1, sizeof(*listener));
165   listener->context = SSL_CTX_new(SSLv23_server_method());
166   if(!listener->context) {
167     goto ssl_create_listener_failed;
168   }
169   
170   char *certfile = conf_get_local()->sslcertfile;
171   char *keyfile = conf_get_local()->sslkeyfile;
172   char *cafile = conf_get_local()->sslcafile;
173   
174   if(!certfile) {
175     goto ssl_create_listener_failed;
176   }
177   if(!keyfile) {
178     keyfile = certfile;
179   }
180   
181   /* load certificate */
182   if(SSL_CTX_use_certificate_file(listener->context, certfile, SSL_FILETYPE_PEM) <= 0) {
183     goto ssl_create_listener_failed;
184   }
185   /* load keyfile */
186   if(SSL_CTX_use_PrivateKey_file(listener->context, keyfile, SSL_FILETYPE_PEM) <= 0) {
187     goto ssl_create_listener_failed;
188   }
189   /* check certificate and keyfile */
190   if(!SSL_CTX_check_private_key(listener->context)) {
191     goto ssl_create_listener_failed;
192   }
193   /* load cafile */
194   if(cafile && cafile[0] && SSL_CTX_load_verify_locations(listener->context, cafile, NULL) <= 0) {
195     goto ssl_create_listener_failed;
196   }
197   FlagSet(&listener->flags, SSLFLAG_READY);
198   return listener;
199 ssl_create_listener_failed:
200   free(listener);
201   return NULL;
202 }
203
204 static int ssl_handshake_incoming(struct SSLConnection *connection) {
205   int result = SSL_accept(connection->session);
206         FlagClr(&connection->flags, SSLFLAG_HANDSHAKE_R);
207   FlagClr(&connection->flags, SSLFLAG_HANDSHAKE_W);
208         switch(SSL_get_error(connection->session, result)) {
209                 case SSL_ERROR_NONE:
210                         FlagClr(&connection->flags, SSLFLAG_HANDSHAKE);
211       FlagSet(&connection->flags, SSLFLAG_READY);
212       
213       ssl_handshake_completed(connection, 1);
214                         return 0;
215                 case SSL_ERROR_WANT_READ:
216                         FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
217       return 1;
218                 case SSL_ERROR_WANT_WRITE:
219       FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
220                         return 1;
221                 default:
222       //unset connection! 
223       //Handshake error!
224       ssl_handshake_completed(connection, 0);
225                         return 0;
226         }
227   return 0;
228 }
229
230 struct SSLConnection *ssl_start_handshake_listener(struct SSLListener *listener, int fd, void *data, enum SSLDataType datatype) {
231   if(!listener)
232     return NULL;
233   struct SSLPendingConections *pending = NULL;
234   struct SSLConnection *connection = malloc(sizeof(*connection));
235   connection->session = SSL_new(listener->context);
236   if(!connection->session) {
237     goto ssl_start_handshake_listener_failed;
238   }
239   if(!SSL_set_fd(connection->session, fd)) {
240     goto ssl_start_handshake_listener_failed;
241   }
242   FlagSet(&connection->flags, SSLFLAG_INCOMING);
243   FlagSet(&connection->flags, SSLFLAG_HANDSHAKE);
244   FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
245   
246   pending = malloc(sizeof(*pending));
247   if(!pending) {
248     goto ssl_start_handshake_listener_failed;
249   }
250   pending->connection = connection;
251   pending->next = firstPendingConection;
252   firstPendingConection = pending;
253   
254   pending->data = data;
255   pending->datatype = datatype;
256   
257   ssl_handshake_incoming(connection);
258         return connection;
259 ssl_start_handshake_listener_failed:
260         free(connection);
261         return NULL;
262 }
263
264 IOResult ssl_recv_decrypt(struct SSLConnection *connection, char *buf, unsigned int buflen, unsigned int *len) {
265   if(FlagHas(&connection->flags, SSLFLAG_HANDSHAKE)) {
266     if(FlagHas(&connection->flags, SSLFLAG_INCOMING)) {
267       ssl_handshake_incoming(connection);
268       return IO_BLOCKED;
269     }
270     if(FlagHas(&connection->flags, SSLFLAG_OUTGOING)) {
271       ssl_handshake_outgoing(connection);
272       return IO_BLOCKED;
273     }
274   }
275   
276   *len = SSL_read(connection->session, buf, buflen);
277   FlagClr(&connection->flags, SSLFLAG_HANDSHAKE_R);
278   int err = SSL_get_error(connection->session, *len);
279   switch(err) {
280     case SSL_ERROR_NONE:
281         return IO_SUCCESS;
282                 case SSL_ERROR_ZERO_RETURN:
283                   return IO_FAILURE;
284                 case SSL_ERROR_WANT_READ:
285       FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
286                         return IO_BLOCKED;
287                 case SSL_ERROR_WANT_WRITE:
288                         FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
289                         return IO_BLOCKED;
290                 case SSL_ERROR_SYSCALL:
291                         return IO_FAILURE;
292                 default:
293       return IO_FAILURE;
294   }
295 }
296
297 static ssize_t ssl_writev(SSL *ssl, const struct iovec *vector, int count) {
298   char *buffer;
299   register char *bp;
300   size_t bytes, to_copy;
301   int i;
302
303   /* Find the total number of bytes to be written.  */
304   bytes = 0;
305   for (i = 0; i < count; ++i)
306     bytes += vector[i].iov_len;
307
308   /* Allocate a temporary buffer to hold the data.  */
309   buffer = (char *) alloca (bytes);
310
311   /* Copy the data into BUFFER.  */
312   to_copy = bytes;
313   bp = buffer;
314   for (i = 0; i < count; ++i) {
315     size_t copy = ((vector[i].iov_len) > (to_copy) ? (to_copy) : (vector[i].iov_len));
316     memcpy ((void *) bp, (void *) vector[i].iov_base, copy);
317     bp += copy;
318     to_copy -= copy;
319     if (to_copy == 0)
320       break;
321   }
322   return SSL_write(ssl, buffer, bytes);
323 }
324
325 IOResult ssl_send_encrypt_plain(struct SSLConnection *connection, char* buf, int len) {
326   return SSL_write(connection->session, buf, len);
327 }
328
329 IOResult ssl_send_encrypt(struct SSLConnection *connection, struct MsgQ* buf, unsigned int *count_in, unsigned int *count_out) {
330   int res;
331   int count;
332   struct iovec iov[IOV_MAX];
333
334   assert(0 != buf);
335   assert(0 != count_in);
336   assert(0 != count_out);
337
338   *count_in = 0;
339   count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
340   res = ssl_writev(connection->session, iov, count);
341
342   switch(SSL_get_error(connection->session, res)) {
343     case SSL_ERROR_NONE:
344                 case SSL_ERROR_ZERO_RETURN:
345       *count_out = (unsigned) res;
346       return IO_SUCCESS;
347     case SSL_ERROR_WANT_READ:
348       FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
349                         return IO_BLOCKED;
350     case SSL_ERROR_WANT_WRITE:
351       FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
352                         return IO_BLOCKED;
353     default:
354       *count_out = 0;
355       return IO_FAILURE;
356   }
357 }
358
359 int ssl_connection_flush(struct SSLConnection *connection) {
360   if(connection) {
361     if(ssl_handshake(connection)) {
362       if(FlagHas(&connection->flags, SSLFLAG_INCOMING)) {
363         return ssl_handshake_incoming(connection);
364       }
365       if(FlagHas(&connection->flags, SSLFLAG_OUTGOING)) {
366         return ssl_handshake_outgoing(connection);
367       }
368     }
369   } else {
370     struct SSLPendingConections *curr, *last = NULL, *next;
371     for(curr = firstPendingConection; curr; curr = next) {
372       next = curr->next;
373       if(!ssl_connection_flush(curr->connection)) {
374         // connection is already in auth process here, curr is freed!
375         continue;
376       }
377       last = curr;
378     }
379   }
380   return 0;
381 }
382
383 const char* ssl_get_cipher(struct SSLConnection *connection) {
384   if(!connection)
385     return NULL;
386   static char buf[400];
387   char buf2[128];
388   int bits;
389   SSL_CIPHER *c;
390
391   buf[0] = '\0';
392   strcpy(buf, SSL_get_version(connection->session));
393   strcat(buf, "-");
394   strcat(buf, SSL_get_cipher(connection->session));
395   c = SSL_get_current_cipher(connection->session);
396   SSL_CIPHER_get_bits(c, &bits);
397   strcat(buf, "-");
398   ircd_snprintf(0, buf2, sizeof(buf2), "%d", bits);
399   strcat(buf, buf2);
400   strcat(buf, "bits");
401   return buf;
402 }