[IOMultiplexerV2] started to implement c-ares backend
[NextIRCd.git] / src / IOHandler / IOSSLBackend.c
1 /* IOSSLBackend.c - IOMultiplexer
2  * Copyright (C) 2014  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
20 #include "IOLog.h"
21 #include "IOSockets.h"
22 #include "IOSSLBackend.h"
23
24 #ifdef HAVE_OPENSSL_SSL_H
25 /* OpenSSL Backend */
26
27
28 void iossl_init() {
29     SSL_library_init();
30     OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
31     SSL_load_error_strings();
32 }
33
34 static void iossl_error() {
35     unsigned long e;
36     while((e = ERR_get_error())) {
37         iolog_trigger(IOLOG_ERROR, "SSLv23 ERROR %lu: %s", e, ERR_error_string(e, NULL));
38     }
39 }
40
41 // Client
42 void iossl_connect(struct _IOSocket *iosock) {
43     struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
44     sslnode->sslContext = SSL_CTX_new(SSLv23_client_method());
45     if(!sslnode->sslContext) {
46         iossl_error();
47         iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL CTX");
48         goto ssl_connect_err;
49     }
50     sslnode->sslHandle = SSL_new(sslnode->sslContext);
51     if(!sslnode->sslHandle) {
52         iossl_error();
53         iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle");
54         goto ssl_connect_err;
55     }
56     if(!SSL_set_fd(sslnode->sslHandle, iosock->fd)) {
57         iossl_error();
58         iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
59         goto ssl_connect_err;
60     }
61     SSL_set_connect_state(sslnode->sslHandle);
62     iosock->sslnode = sslnode;
63         iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
64     iossl_client_handshake(iosock);
65     return;
66 ssl_connect_err:
67     free(sslnode);
68     iosocket_events_callback(iosock, 0, 0);
69 }
70
71 void iossl_client_handshake(struct _IOSocket *iosock) {
72     // Perform an SSL handshake.
73     int ret = SSL_do_handshake(iosock->sslnode->sslHandle);
74     iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
75     switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
76         case SSL_ERROR_NONE:
77             iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd);
78                         iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
79             iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
80             break;
81         case SSL_ERROR_WANT_READ:
82             iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
83             break;
84         case SSL_ERROR_WANT_WRITE:
85             iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
86             iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
87             break;
88         default:
89             iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd);
90             iosocket_events_callback(iosock, 0, 0);
91             break;
92     }
93 }
94
95
96 // Server
97 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {
98     struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
99     sslnode->sslContext = SSL_CTX_new(SSLv23_server_method());
100     if(!sslnode->sslContext) {
101         iossl_error();
102         iolog_trigger(IOLOG_ERROR, "SSL: could not create server SSL CTX");
103         goto ssl_listen_err;
104     }
105     /* load certificate */
106     if(SSL_CTX_use_certificate_file(sslnode->sslContext, certfile, SSL_FILETYPE_PEM) <= 0) {
107         iossl_error();
108         iolog_trigger(IOLOG_ERROR, "SSL: could not load server certificate (%s)", certfile);
109         goto ssl_listen_err;
110     }
111     /* load keyfile */
112     if(SSL_CTX_use_PrivateKey_file(sslnode->sslContext, keyfile, SSL_FILETYPE_PEM) <= 0) {
113         iossl_error();
114         iolog_trigger(IOLOG_ERROR, "SSL: could not load server keyfile (%s)", keyfile);
115         goto ssl_listen_err;
116     }
117     /* check certificate and keyfile */
118     if(!SSL_CTX_check_private_key(sslnode->sslContext)) {
119         iossl_error();
120         iolog_trigger(IOLOG_ERROR, "SSL: server certificate (%s) and keyfile (%s) doesn't match!", certfile, keyfile);
121         goto ssl_listen_err;
122     }
123     iosock->sslnode = sslnode;\r
124     iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
125     return;
126 ssl_listen_err:
127     free(sslnode);
128     iosock->sslnode = NULL;
129     iosocket_events_callback(iosock, 0, 0);
130 }
131
132 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *new_iosock) {
133     struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
134     sslnode->sslHandle = SSL_new(sslnode->sslContext);
135     if(!sslnode->sslHandle) {
136         iossl_error();
137         iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle");
138         goto ssl_accept_err;
139     }
140     if(!SSL_set_fd(sslnode->sslHandle, new_iosock->fd)) {
141         iossl_error();
142         iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
143         goto ssl_accept_err;
144     }
145     new_iosock->sslnode = sslnode;\r
146     new_iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
147     return;
148 ssl_accept_err:
149     free(sslnode);\r
150     iosock->sslnode = NULL;\r
151     iosocket_events_callback(new_iosock, 0, 0);
152 }
153
154 void iossl_server_handshake(struct _IOSocket *iosock) {
155     // Perform an SSL handshake.
156     int ret = SSL_accept(iosock->sslnode->sslHandle);
157     iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
158     switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
159         case SSL_ERROR_NONE:
160             iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd);
161                         iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
162             iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
163             break;
164         case SSL_ERROR_WANT_READ:
165             iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
166             break;
167         case SSL_ERROR_WANT_WRITE:
168             iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
169             iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
170             break;
171         default:
172             iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd);
173             iosocket_events_callback(iosock, 0, 0);
174             break;
175     }
176 }
177
178 void iossl_disconnect(struct _IOSocket *iosock) {
179     if(!iosock->sslnode) return;
180     SSL_shutdown(iosock->sslnode->sslHandle);
181     SSL_free(iosock->sslnode->sslHandle);
182     SSL_CTX_free(iosock->sslnode->sslContext);
183     free(iosock->sslnode);
184     iosock->sslnode = NULL;
185     iosock->socket_flags &= ~IOSOCKETFLAG_SSLSOCKET;
186 }
187
188 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) {
189     if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))\r
190                 return 0;
191     int ret = SSL_read(iosock->sslnode->sslHandle, buffer, len);
192     iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS);
193     switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
194         case SSL_ERROR_NONE:
195         case SSL_ERROR_ZERO_RETURN:
196             break;
197         case SSL_ERROR_WANT_READ:\r
198                         iosock->socket_flags |= IOSOCKETFLAG_SSL_READHS;
199             iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
200             errno = EAGAIN;
201             ret = -1;
202             break;
203         case SSL_ERROR_WANT_WRITE:
204             iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS;
205             iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
206             errno = EAGAIN;
207             ret = -1;
208             break;
209         default:
210             iolog_trigger(IOLOG_ERROR, "SSL_read for fd %d failed with ", iosock->fd);
211             ret = -1;
212             break;
213     }\r
214     return ret;
215 }
216
217 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) {
218     if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))\r
219                 return 0;
220     int ret = SSL_write(iosock->sslnode->sslHandle, buffer, len);
221     iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS);
222     switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
223         case SSL_ERROR_NONE:
224         case SSL_ERROR_ZERO_RETURN:
225             break;
226         case SSL_ERROR_WANT_READ:
227             iosock->socket_flags |= IOSOCKETFLAG_SSL_WRITEHS;
228             iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
229             errno = EAGAIN;
230             ret = -1;
231             break;
232         case SSL_ERROR_WANT_WRITE:
233             iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS;
234             iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
235             errno = EAGAIN;
236             ret = -1;
237             break;
238         default:
239             iolog_trigger(IOLOG_ERROR, "SSL_write for fd %d failed with ", iosock->fd);
240             ret = -1;
241             break;
242     }\r
243     return ret;
244 }
245
246 #else
247 // NULL-backend
248
249 void iossl_init() {};
250 void iossl_connect(struct _IOSocket *iosock) {};
251 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {};
252 void iossl_client_handshake(struct _IOSocket *iosock) {};
253 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *client_iofd) {};
254 void iossl_server_handshake(struct _IOSocket *iosock) {};
255 void iossl_disconnect(struct _IOSocket *iosock) {};
256 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) { return 0; };
257 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) { return 0; };
258 #endif