1 /* IOSSLBackend.c - IOMultiplexer
2 * Copyright (C) 2014 Philipp Kreil (pk910)
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.
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.
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/>.
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
21 #include "IOSockets.h"
22 #include "IOSSLBackend.h"
24 #if defined(HAVE_GNUTLS_GNUTLS_H)
29 static gnutls_dh_params_t dh_params;
31 static int generate_dh_params() {
32 unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
33 gnutls_dh_params_init(&dh_params);
34 gnutls_dh_params_generate2(dh_params, bits);
40 if((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS) {
41 iolog_trigger(IOLOG_ERROR, "SSL: gnutls_global_init(): failed (%d)", ret);
42 //TODO: Error handling?
49 void iossl_connect(struct _IOSocket *iosock) {
50 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
53 err = gnutls_certificate_allocate_credentials(&sslnode->ssl.client.credentials);
58 gnutls_init(&sslnode->ssl.client.session, GNUTLS_CLIENT);
60 gnutls_priority_set_direct(sslnode->ssl.client.session, "NONE:+VERS-TLS1.0:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL", NULL);
61 gnutls_credentials_set(sslnode->ssl.client.session, GNUTLS_CRD_CERTIFICATE, sslnode->ssl.client.credentials);
63 gnutls_transport_set_int(sslnode->ssl.client.session, iosock->fd);
64 gnutls_handshake_set_timeout(sslnode->ssl.client.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
66 iosock->sslnode = sslnode;
67 iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
68 iossl_client_handshake(iosock);
72 iosocket_events_callback(iosock, 0, 0);
75 void iossl_client_handshake(struct _IOSocket *iosock) {
76 // Perform an SSL handshake.
77 int ret = gnutls_handshake(iosock->sslnode->ssl.client.session);
78 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
81 if(gnutls_error_is_fatal(ret) == 0) {
82 if(gnutls_record_get_direction(iosock->sslnode->ssl.client.session)) {
83 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
84 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to write...", iosock->fd);
86 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to read...", iosock->fd);
89 iolog_trigger(IOLOG_ERROR, "gnutls_handshake for fd %d failed with %s", iosock->fd, gnutls_strerror(ret));
90 iosocket_events_callback(iosock, 0, 0);
94 desc = gnutls_session_get_desc(iosock->sslnode->ssl.client.session);
95 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful: %s", iosock->fd, desc);
97 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
98 iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
104 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {
105 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
107 gnutls_priority_init(&sslnode->ssl.server.priority, "NONE:+VERS-TLS1.0:+VERS-SSL3.0:+CIPHER-ALL:+COMP-ALL:+RSA:+DHE-RSA:+DHE-DSS:+MAC-ALL", NULL);
109 gnutls_certificate_allocate_credentials(&sslnode->ssl.server.credentials);
110 int ret = gnutls_certificate_set_x509_key_file(sslnode->ssl.server.credentials, certfile, keyfile, GNUTLS_X509_FMT_PEM);
112 iolog_trigger(IOLOG_ERROR, "SSL: could not load server certificate/key (%s %s): %d - %s", certfile, keyfile, ret, gnutls_strerror(ret));
116 gnutls_certificate_set_dh_params(sslnode->ssl.server.credentials, dh_params);
118 iosock->sslnode = sslnode;
119 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
123 iosock->sslnode = NULL;
124 iosocket_events_callback(iosock, 0, 0);
127 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *new_iosock) {
128 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
130 gnutls_init(&sslnode->ssl.client.session, GNUTLS_SERVER);
131 gnutls_priority_set(sslnode->ssl.client.session, iosock->sslnode->ssl.server.priority);
132 gnutls_credentials_set(sslnode->ssl.client.session, GNUTLS_CRD_CERTIFICATE, iosock->sslnode->ssl.server.credentials);
134 /* We don't request any certificate from the client.
135 * If we did we would need to verify it.
137 gnutls_certificate_server_set_request(sslnode->ssl.client.session, GNUTLS_CERT_IGNORE);
139 gnutls_transport_set_int(sslnode->ssl.client.session, new_iosock->fd);
141 new_iosock->sslnode = sslnode;
142 new_iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
147 iosock->sslnode = NULL;
148 iosocket_events_callback(new_iosock, 0, 0);
152 void iossl_server_handshake(struct _IOSocket *iosock) {
153 return iossl_client_handshake(iosock);
156 void iossl_disconnect(struct _IOSocket *iosock) {
157 if(!iosock->sslnode) return;
159 if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
160 gnutls_certificate_free_credentials(iosock->sslnode->ssl.server.credentials);
161 gnutls_priority_deinit(iosock->sslnode->ssl.server.priority);
163 gnutls_bye(iosock->sslnode->ssl.client.session, GNUTLS_SHUT_RDWR);
164 gnutls_certificate_free_credentials(iosock->sslnode->ssl.client.credentials);
165 gnutls_deinit(iosock->sslnode->ssl.client.session);
168 free(iosock->sslnode);
169 iosock->sslnode = NULL;
170 iosock->socket_flags &= ~IOSOCKETFLAG_SSLSOCKET;
173 static void iossl_rehandshake(struct _IOSocket *iosock, int hsflag) {
174 int ret = gnutls_handshake(iosock->sslnode->ssl.client.session);
175 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
178 if(gnutls_error_is_fatal(ret) == 0) {
179 if(gnutls_record_get_direction(iosock->sslnode->ssl.client.session)) {
180 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | hsflag;
181 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to write...", iosock->fd);
183 iosock->socket_flags |= hsflag;
184 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to read...", iosock->fd);
187 iolog_trigger(IOLOG_ERROR, "gnutls_handshake for fd %d failed: %s", iosock->fd, gnutls_strerror(ret));
188 //TODO: Error Action?
192 desc = gnutls_session_get_desc(iosock->sslnode->ssl.client.session);
193 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful: %s", iosock->fd, desc);
195 iosock->socket_flags &= ~hsflag;
199 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) {
200 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
202 if((iosock->socket_flags & IOSOCKETFLAG_SSL_READHS)) {
203 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_READHS);
207 int ret = gnutls_record_recv(iosock->sslnode->ssl.client.session, buffer, len);
211 } else if(ret < 0 && gnutls_error_is_fatal(ret) == 0) {
212 iolog_trigger(IOLOG_WARNING, "gnutls_record_recv for fd %d returned %s", iosock->fd, gnutls_strerror(ret));
213 if(ret == GNUTLS_E_REHANDSHAKE) {
214 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_READHS);
219 iolog_trigger(IOLOG_ERROR, "gnutls_record_recv for fd %d failed: %s", iosock->fd, gnutls_strerror(ret));
226 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) {
227 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
229 if((iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) {
230 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_WRITEHS);
234 int ret = gnutls_record_send(iosock->sslnode->ssl.client.session, buffer, len);
235 if(ret < 0 && gnutls_error_is_fatal(ret) == 0) {
236 iolog_trigger(IOLOG_WARNING, "gnutls_record_send for fd %d returned %s", iosock->fd, gnutls_strerror(ret));
237 if(ret == GNUTLS_E_REHANDSHAKE) {
238 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_WRITEHS);
243 iolog_trigger(IOLOG_ERROR, "gnutls_record_send for fd %d failed: %s", iosock->fd, gnutls_strerror(ret));
250 #elif defined(HAVE_OPENSSL_SSL_H)
251 /* OpenSSL Backend */
256 OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
257 SSL_load_error_strings();
260 static void iossl_error() {
262 while((e = ERR_get_error())) {
263 iolog_trigger(IOLOG_ERROR, "SSLv23 ERROR %lu: %s", e, ERR_error_string(e, NULL));
268 void iossl_connect(struct _IOSocket *iosock) {
269 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
270 sslnode->sslContext = SSL_CTX_new(SSLv23_client_method());
271 if(!sslnode->sslContext) {
273 iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL CTX");
274 goto ssl_connect_err;
276 sslnode->sslHandle = SSL_new(sslnode->sslContext);
277 if(!sslnode->sslHandle) {
279 iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle");
280 goto ssl_connect_err;
282 if(!SSL_set_fd(sslnode->sslHandle, iosock->fd)) {
284 iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
285 goto ssl_connect_err;
287 SSL_set_connect_state(sslnode->sslHandle);
288 iosock->sslnode = sslnode;
289 iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
290 iossl_client_handshake(iosock);
294 iosocket_events_callback(iosock, 0, 0);
297 void iossl_client_handshake(struct _IOSocket *iosock) {
298 // Perform an SSL handshake.
299 int ret = SSL_do_handshake(iosock->sslnode->sslHandle);
300 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
301 switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
303 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd);
304 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
305 iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
307 case SSL_ERROR_WANT_READ:
308 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
310 case SSL_ERROR_WANT_WRITE:
311 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
312 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
315 iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd);
316 iosocket_events_callback(iosock, 0, 0);
323 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {
324 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
325 sslnode->sslContext = SSL_CTX_new(SSLv23_server_method());
326 if(!sslnode->sslContext) {
328 iolog_trigger(IOLOG_ERROR, "SSL: could not create server SSL CTX");
331 /* load certificate */
332 if(SSL_CTX_use_certificate_file(sslnode->sslContext, certfile, SSL_FILETYPE_PEM) <= 0) {
334 iolog_trigger(IOLOG_ERROR, "SSL: could not load server certificate (%s)", certfile);
338 if(SSL_CTX_use_PrivateKey_file(sslnode->sslContext, keyfile, SSL_FILETYPE_PEM) <= 0) {
340 iolog_trigger(IOLOG_ERROR, "SSL: could not load server keyfile (%s)", keyfile);
343 /* check certificate and keyfile */
344 if(!SSL_CTX_check_private_key(sslnode->sslContext)) {
346 iolog_trigger(IOLOG_ERROR, "SSL: server certificate (%s) and keyfile (%s) doesn't match!", certfile, keyfile);
349 iosock->sslnode = sslnode;
\r
350 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
354 iosock->sslnode = NULL;
355 iosocket_events_callback(iosock, 0, 0);
358 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *new_iosock) {
359 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
360 sslnode->sslHandle = SSL_new(iosock->sslnode->sslContext);
361 if(!sslnode->sslHandle) {
363 iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle");
366 if(!SSL_set_fd(sslnode->sslHandle, new_iosock->fd)) {
368 iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
371 new_iosock->sslnode = sslnode;
\r
372 new_iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
376 iosock->sslnode = NULL;
\r
377 iosocket_events_callback(new_iosock, 0, 0);
380 void iossl_server_handshake(struct _IOSocket *iosock) {
381 // Perform an SSL handshake.
382 int ret = SSL_accept(iosock->sslnode->sslHandle);
383 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
384 switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
386 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd);
387 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
388 iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
390 case SSL_ERROR_WANT_READ:
391 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
393 case SSL_ERROR_WANT_WRITE:
394 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
395 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
398 iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd);
399 iosocket_events_callback(iosock, 0, 0);
404 void iossl_disconnect(struct _IOSocket *iosock) {
405 if(!iosock->sslnode) return;
406 SSL_shutdown(iosock->sslnode->sslHandle);
407 SSL_free(iosock->sslnode->sslHandle);
408 SSL_CTX_free(iosock->sslnode->sslContext);
409 free(iosock->sslnode);
410 iosock->sslnode = NULL;
411 iosock->socket_flags &= ~IOSOCKETFLAG_SSLSOCKET;
414 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) {
415 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
\r
417 int ret = SSL_read(iosock->sslnode->sslHandle, buffer, len);
418 iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS);
419 switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
421 case SSL_ERROR_ZERO_RETURN:
423 case SSL_ERROR_WANT_READ:
\r
424 iosock->socket_flags |= IOSOCKETFLAG_SSL_READHS;
425 iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
429 case SSL_ERROR_WANT_WRITE:
430 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS;
431 iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
436 iolog_trigger(IOLOG_ERROR, "SSL_read for fd %d failed with ", iosock->fd);
443 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) {
444 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
\r
446 int ret = SSL_write(iosock->sslnode->sslHandle, buffer, len);
447 iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS);
448 switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
450 case SSL_ERROR_ZERO_RETURN:
452 case SSL_ERROR_WANT_READ:
453 iosock->socket_flags |= IOSOCKETFLAG_SSL_WRITEHS;
454 iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
458 case SSL_ERROR_WANT_WRITE:
459 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS;
460 iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
465 iolog_trigger(IOLOG_ERROR, "SSL_write for fd %d failed with ", iosock->fd);
475 void iossl_init() {};
476 void iossl_connect(struct _IOSocket *iosock) {};
477 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {};
478 void iossl_client_handshake(struct _IOSocket *iosock) {};
479 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *client_iofd) {};
480 void iossl_server_handshake(struct _IOSocket *iosock) {};
481 void iossl_disconnect(struct _IOSocket *iosock) {};
482 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) { return 0; };
483 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) { return 0; };