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;
30 static unsigned int dh_params_bits;
32 static int generate_dh_params() {
33 dh_params_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
34 gnutls_dh_params_init(&dh_params);
35 gnutls_dh_params_generate2(dh_params, dh_params_bits);
41 if((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS) {
42 iolog_trigger(IOLOG_ERROR, "SSL: gnutls_global_init(): failed (%d)", ret);
43 //TODO: Error handling?
50 void iossl_connect(struct _IOSocket *iosock) {
51 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
54 err = gnutls_certificate_allocate_credentials(&sslnode->ssl.client.credentials);
59 gnutls_init(&sslnode->ssl.client.session, GNUTLS_CLIENT);
61 gnutls_priority_set_direct(sslnode->ssl.client.session, "SECURE128:+SECURE192:-VERS-TLS-ALL:+VERS-TLS1.2", NULL);
62 gnutls_credentials_set(sslnode->ssl.client.session, GNUTLS_CRD_CERTIFICATE, sslnode->ssl.client.credentials);
64 gnutls_transport_set_int(sslnode->ssl.client.session, iosock->fd);
65 gnutls_handshake_set_timeout(sslnode->ssl.client.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
67 iosock->sslnode = sslnode;
68 iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
69 iossl_client_handshake(iosock);
73 iosocket_events_callback(iosock, 0, 0);
76 void iossl_client_handshake(struct _IOSocket *iosock) {
77 // Perform an SSL handshake.
78 int ret = gnutls_handshake(iosock->sslnode->ssl.client.session);
79 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
82 if(gnutls_error_is_fatal(ret) == 0) {
83 if(gnutls_record_get_direction(iosock->sslnode->ssl.client.session)) {
84 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
85 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to write...", iosock->fd);
87 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to read...", iosock->fd);
90 iolog_trigger(IOLOG_ERROR, "gnutls_handshake for fd %d failed with %s", iosock->fd, gnutls_strerror(ret));
91 iosocket_events_callback(iosock, 0, 0);
95 desc = gnutls_session_get_desc(iosock->sslnode->ssl.client.session);
96 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful: %s", iosock->fd, desc);
98 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
99 iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
105 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {
106 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
108 gnutls_priority_init(&sslnode->ssl.server.priority, "SECURE128:+SECURE192:-VERS-TLS-ALL:+VERS-TLS1.2", NULL);
110 gnutls_certificate_allocate_credentials(&sslnode->ssl.server.credentials);
111 int ret = gnutls_certificate_set_x509_key_file(sslnode->ssl.server.credentials, certfile, keyfile, GNUTLS_X509_FMT_PEM);
113 iolog_trigger(IOLOG_ERROR, "SSL: could not load server certificate/key (%s %s): %d - %s", certfile, keyfile, ret, gnutls_strerror(ret));
117 gnutls_certificate_set_dh_params(sslnode->ssl.server.credentials, dh_params);
119 iosock->sslnode = sslnode;
120 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
124 iosock->sslnode = NULL;
125 iosocket_events_callback(iosock, 0, 0);
128 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *new_iosock) {
129 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
131 gnutls_init(&sslnode->ssl.client.session, GNUTLS_SERVER);
132 gnutls_priority_set(sslnode->ssl.client.session, iosock->sslnode->ssl.server.priority);
133 gnutls_credentials_set(sslnode->ssl.client.session, GNUTLS_CRD_CERTIFICATE, iosock->sslnode->ssl.server.credentials);
134 gnutls_dh_set_prime_bits(sslnode->ssl.client.session, dh_params_bits);
136 /* We don't request any certificate from the client.
137 * If we did we would need to verify it.
139 gnutls_certificate_server_set_request(sslnode->ssl.client.session, GNUTLS_CERT_IGNORE);
141 gnutls_transport_set_int(sslnode->ssl.client.session, new_iosock->fd);
143 new_iosock->sslnode = sslnode;
144 new_iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
149 iosock->sslnode = NULL;
150 iosocket_events_callback(new_iosock, 0, 0);
154 void iossl_server_handshake(struct _IOSocket *iosock) {
155 return iossl_client_handshake(iosock);
158 void iossl_disconnect(struct _IOSocket *iosock) {
159 if(!iosock->sslnode) return;
161 if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
162 gnutls_certificate_free_credentials(iosock->sslnode->ssl.server.credentials);
163 gnutls_priority_deinit(iosock->sslnode->ssl.server.priority);
165 gnutls_bye(iosock->sslnode->ssl.client.session, GNUTLS_SHUT_RDWR);
166 if(!(iosock->socket_flags & IOSOCKETFLAG_INCOMING))
167 gnutls_certificate_free_credentials(iosock->sslnode->ssl.client.credentials);
168 gnutls_deinit(iosock->sslnode->ssl.client.session);
171 free(iosock->sslnode);
172 iosock->sslnode = NULL;
173 iosock->socket_flags &= ~IOSOCKETFLAG_SSLSOCKET;
176 static void iossl_rehandshake(struct _IOSocket *iosock, int hsflag) {
177 int ret = gnutls_handshake(iosock->sslnode->ssl.client.session);
178 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
181 if(gnutls_error_is_fatal(ret) == 0) {
182 if(gnutls_record_get_direction(iosock->sslnode->ssl.client.session)) {
183 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | hsflag;
184 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to write...", iosock->fd);
186 iosock->socket_flags |= hsflag;
187 iolog_trigger(IOLOG_DEBUG, "gnutls_handshake for fd %d wants to read...", iosock->fd);
190 iolog_trigger(IOLOG_ERROR, "gnutls_handshake for fd %d failed: %s", iosock->fd, gnutls_strerror(ret));
191 //TODO: Error Action?
195 desc = gnutls_session_get_desc(iosock->sslnode->ssl.client.session);
196 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful: %s", iosock->fd, desc);
198 iosock->socket_flags &= ~hsflag;
202 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) {
203 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
205 if((iosock->socket_flags & IOSOCKETFLAG_SSL_READHS)) {
206 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_READHS);
210 int ret = gnutls_record_recv(iosock->sslnode->ssl.client.session, buffer, len);
214 } else if(ret < 0 && gnutls_error_is_fatal(ret) == 0) {
215 iolog_trigger(IOLOG_WARNING, "gnutls_record_recv for fd %d returned %s", iosock->fd, gnutls_strerror(ret));
216 if(ret == GNUTLS_E_REHANDSHAKE) {
217 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_READHS);
222 iolog_trigger(IOLOG_ERROR, "gnutls_record_recv for fd %d failed: %s", iosock->fd, gnutls_strerror(ret));
229 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) {
230 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
232 if((iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) {
233 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_WRITEHS);
237 int ret = gnutls_record_send(iosock->sslnode->ssl.client.session, buffer, len);
238 if(ret < 0 && gnutls_error_is_fatal(ret) == 0) {
239 iolog_trigger(IOLOG_WARNING, "gnutls_record_send for fd %d returned %s", iosock->fd, gnutls_strerror(ret));
240 if(ret == GNUTLS_E_REHANDSHAKE) {
241 iossl_rehandshake(iosock, IOSOCKETFLAG_SSL_WRITEHS);
246 iolog_trigger(IOLOG_ERROR, "gnutls_record_send for fd %d failed: %s", iosock->fd, gnutls_strerror(ret));
253 #elif defined(HAVE_OPENSSL_SSL_H)
254 /* OpenSSL Backend */
259 OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
260 SSL_load_error_strings();
263 static void iossl_error() {
265 while((e = ERR_get_error())) {
266 iolog_trigger(IOLOG_ERROR, "SSLv23 ERROR %lu: %s", e, ERR_error_string(e, NULL));
271 void iossl_connect(struct _IOSocket *iosock) {
272 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
273 sslnode->sslContext = SSL_CTX_new(SSLv23_client_method());
274 if(!sslnode->sslContext) {
276 iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL CTX");
277 goto ssl_connect_err;
279 sslnode->sslHandle = SSL_new(sslnode->sslContext);
280 if(!sslnode->sslHandle) {
282 iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle");
283 goto ssl_connect_err;
285 if(!SSL_set_fd(sslnode->sslHandle, iosock->fd)) {
287 iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
288 goto ssl_connect_err;
290 SSL_set_connect_state(sslnode->sslHandle);
291 iosock->sslnode = sslnode;
292 iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
293 iossl_client_handshake(iosock);
297 iosocket_events_callback(iosock, 0, 0);
300 void iossl_client_handshake(struct _IOSocket *iosock) {
301 // Perform an SSL handshake.
302 int ret = SSL_do_handshake(iosock->sslnode->sslHandle);
303 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
304 switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
306 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd);
307 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
308 iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
310 case SSL_ERROR_WANT_READ:
311 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
313 case SSL_ERROR_WANT_WRITE:
314 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
315 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
318 iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd);
319 iosocket_events_callback(iosock, 0, 0);
326 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {
327 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
328 sslnode->sslContext = SSL_CTX_new(SSLv23_server_method());
329 if(!sslnode->sslContext) {
331 iolog_trigger(IOLOG_ERROR, "SSL: could not create server SSL CTX");
334 /* load certificate */
335 if(SSL_CTX_use_certificate_file(sslnode->sslContext, certfile, SSL_FILETYPE_PEM) <= 0) {
337 iolog_trigger(IOLOG_ERROR, "SSL: could not load server certificate (%s)", certfile);
341 if(SSL_CTX_use_PrivateKey_file(sslnode->sslContext, keyfile, SSL_FILETYPE_PEM) <= 0) {
343 iolog_trigger(IOLOG_ERROR, "SSL: could not load server keyfile (%s)", keyfile);
346 /* check certificate and keyfile */
347 if(!SSL_CTX_check_private_key(sslnode->sslContext)) {
349 iolog_trigger(IOLOG_ERROR, "SSL: server certificate (%s) and keyfile (%s) doesn't match!", certfile, keyfile);
352 iosock->sslnode = sslnode;
353 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
357 iosock->sslnode = NULL;
358 iosocket_events_callback(iosock, 0, 0);
361 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *new_iosock) {
362 struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode));
363 sslnode->sslHandle = SSL_new(iosock->sslnode->sslContext);
364 if(!sslnode->sslHandle) {
366 iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle");
369 if(!SSL_set_fd(sslnode->sslHandle, new_iosock->fd)) {
371 iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
374 new_iosock->sslnode = sslnode;
375 new_iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE;
379 iosock->sslnode = NULL;
380 iosocket_events_callback(new_iosock, 0, 0);
383 void iossl_server_handshake(struct _IOSocket *iosock) {
384 // Perform an SSL handshake.
385 int ret = SSL_accept(iosock->sslnode->sslHandle);
386 iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE;
387 switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
389 iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd);
390 iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED;
391 iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event
393 case SSL_ERROR_WANT_READ:
394 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
396 case SSL_ERROR_WANT_WRITE:
397 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE;
398 iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
401 iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd);
402 iosocket_events_callback(iosock, 0, 0);
407 void iossl_disconnect(struct _IOSocket *iosock) {
408 if(!iosock->sslnode) return;
409 SSL_shutdown(iosock->sslnode->sslHandle);
410 SSL_free(iosock->sslnode->sslHandle);
411 if(!(iosock->socket_flags & IOSOCKETFLAG_INCOMING))
412 SSL_CTX_free(iosock->sslnode->sslContext);
413 free(iosock->sslnode);
414 iosock->sslnode = NULL;
415 iosock->socket_flags &= ~IOSOCKETFLAG_SSLSOCKET;
418 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) {
419 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
421 int ret = SSL_read(iosock->sslnode->sslHandle, buffer, len);
422 iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS);
423 int err = SSL_get_error(iosock->sslnode->sslHandle, ret);
426 case SSL_ERROR_ZERO_RETURN:
428 case SSL_ERROR_WANT_READ:
429 iosock->socket_flags |= IOSOCKETFLAG_SSL_READHS;
430 iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
434 case SSL_ERROR_WANT_WRITE:
435 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS;
436 iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
440 case SSL_ERROR_SYSCALL:
441 iolog_trigger(IOLOG_ERROR, "SSL_read for fd %d failed with SSL_ERROR_SYSCALL: %d", iosock->fd, errno);
445 iolog_trigger(IOLOG_ERROR, "SSL_read for fd %d failed with %d", iosock->fd, err);
452 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) {
453 if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED))
455 int ret = SSL_write(iosock->sslnode->sslHandle, buffer, len);
456 iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS);
457 switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) {
459 case SSL_ERROR_ZERO_RETURN:
461 case SSL_ERROR_WANT_READ:
462 iosock->socket_flags |= IOSOCKETFLAG_SSL_WRITEHS;
463 iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_READ", iosock->fd);
467 case SSL_ERROR_WANT_WRITE:
468 iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS;
469 iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd);
474 iolog_trigger(IOLOG_ERROR, "SSL_write for fd %d failed with ", iosock->fd);
484 void iossl_init() {};
485 void iossl_connect(struct _IOSocket *iosock) {};
486 void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {};
487 void iossl_client_handshake(struct _IOSocket *iosock) {};
488 void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *client_iofd) {};
489 void iossl_server_handshake(struct _IOSocket *iosock) {};
490 void iossl_disconnect(struct _IOSocket *iosock) {};
491 int iossl_read(struct _IOSocket *iosock, char *buffer, int len) { return 0; };
492 int iossl_write(struct _IOSocket *iosock, char *buffer, int len) { return 0; };