added SSL backend for IOMultiplexer
[TransparentIRC.git] / src / IOHandler_SSL.c
1 /* IOHandler_SSL.c - TransparentIRC 0.1
2  * Copyright (C) 2011-2012  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 #include "IOHandler.h"
18 #include "IOEngine.h"
19 #include "IOHandler_SSL.h"
20
21 void iohandler_ssl_init() {
22 #ifdef HAVE_SSL
23     SSL_library_init();
24     SSL_load_error_strings();
25 #endif
26 }
27
28 void iohandler_ssl_connect(struct IODescriptor *iofd) {
29 #ifdef HAVE_SSL
30     iofd->state = IO_SSLWAIT;
31     struct IOSSLNode *sslnode = malloc(sizeof(*sslnode));
32     sslnode->sslContext = SSL_CTX_new(SSLv23_client_method());
33     if(!sslnode->sslContext)
34         goto ssl_connect_err;
35     sslnode->sslHandle = SSL_new(sslnode->sslContext);
36     if(!sslnode->sslHandle) 
37         goto ssl_connect_err;
38     if(!SSL_set_fd(sslnode->sslHandle, iofd->fd))
39         goto ssl_connect_err;
40     SSL_set_connect_state(sslnode->sslHandle);
41     iofd->sslnode = sslnode;
42     iohandler_ssl_client_handshake(iofd);
43     return;
44 ssl_connect_err:
45     free(sslnode);
46     iohandler_events(iofd, 0, 0);
47 #endif    
48 }
49
50 void iohandler_ssl_client_handshake(struct IODescriptor *iofd) {
51     // Perform an SSL handshake.
52     int ret = SSL_do_handshake(iofd->sslnode->sslHandle);
53     iofd->ssl_hs_read = 0;
54     iofd->ssl_hs_write = 0;
55     switch(SSL_get_error(iofd->sslnode->sslHandle, ret)) {
56         case SSL_ERROR_NONE:
57             iofd->state = IO_CONNECTING;
58             iofd->ssl_active = 1;
59             iohandler_log(IOLOG_DEBUG, "SSL handshake for %s (fd: %d) successful", iohandler_iotype_name(iofd->type), iofd->fd);
60             iohandler_events(iofd, 0, 1); //perform IOEVENT_CONNECTED event
61             break;
62         case SSL_ERROR_WANT_READ:
63             iofd->ssl_hs_read = 1;
64             iohandler_log(IOLOG_DEBUG, "SSL_do_handshake for %s (fd: %d) returned SSL_ERROR_WANT_READ", iohandler_iotype_name(iofd->type), iofd->fd);
65             break;
66         case SSL_ERROR_WANT_WRITE:
67             iofd->ssl_hs_write = 1;
68             iohandler_log(IOLOG_DEBUG, "SSL_do_handshake for %s (fd: %d) returned SSL_ERROR_WANT_WRITE", iohandler_iotype_name(iofd->type), iofd->fd);
69             break;
70         default:
71             iohandler_log(IOLOG_ERROR, "SSL_do_handshake for %s (fd: %d) failed with ", iohandler_iotype_name(iofd->type), iofd->fd);
72             iohandler_events(iofd, 0, 0);
73             break;
74     }
75 }
76
77 void iohandler_ssl_disconnect(struct IODescriptor *iofd) {
78 #ifdef HAVE_SSL
79     if(!iofd->sslnode) return;
80     SSL_shutdown(iofd->sslnode->sslHandle);
81     SSL_free(iofd->sslnode->sslHandle);
82     SSL_CTX_free(iofd->sslnode->sslContext);
83     free(iofd->sslnode);
84     iofd->sslnode = NULL;
85     iofd->ssl_active = 0;
86 #endif
87 }
88
89 int iohandler_ssl_read(struct IODescriptor *iofd, char *buffer, int len) {
90 #ifdef HAVE_SSL
91     if(!iofd->sslnode) return 0;
92     int ret = SSL_read(iofd->sslnode->sslHandle, buffer, len);
93     int update = (iofd->ssl_hs_read || iofd->ssl_hs_write);
94     iofd->ssl_hs_read = 0;
95     iofd->ssl_hs_write = 0;
96     switch(SSL_get_error(iofd->sslnode->sslHandle, ret)) {
97         case SSL_ERROR_NONE:
98         case SSL_ERROR_ZERO_RETURN:
99             if(update)
100                 iohandler_update(iofd);
101             return ret;
102             break;
103         case SSL_ERROR_WANT_READ:
104             iofd->ssl_hs_read = 1;
105             iohandler_update(iofd);
106             iohandler_log(IOLOG_DEBUG, "SSL_read for %s (fd: %d) returned SSL_ERROR_WANT_READ", iohandler_iotype_name(iofd->type), iofd->fd);
107             errno = EAGAIN;
108             return -1;
109             break;
110         case SSL_ERROR_WANT_WRITE:
111             iofd->ssl_hs_write = 1;
112             iohandler_update(iofd);
113             iohandler_log(IOLOG_DEBUG, "SSL_read for %s (fd: %d) returned SSL_ERROR_WANT_WRITE", iohandler_iotype_name(iofd->type), iofd->fd);
114             errno = EAGAIN;
115             return -1;
116             break;
117         default:
118             iohandler_log(IOLOG_ERROR, "SSL_read for %s (fd: %d) failed with ", iohandler_iotype_name(iofd->type), iofd->fd);
119             return -1;
120             break;
121     }
122 #endif
123     return 0;
124 }
125
126 int iohandler_ssl_write(struct IODescriptor *iofd, char *buffer, int len) {
127 #ifdef HAVE_SSL
128     if(!iofd->sslnode) return 0;
129     int ret = SSL_write(iofd->sslnode->sslHandle, buffer, len);
130     int update = (iofd->ssl_hs_read || iofd->ssl_hs_write);
131     iofd->ssl_hs_read = 0;
132     iofd->ssl_hs_write = 0;
133     switch(SSL_get_error(iofd->sslnode->sslHandle, ret)) {
134         case SSL_ERROR_NONE:
135         case SSL_ERROR_ZERO_RETURN:
136             if(update)
137                 iohandler_update(iofd);
138             return ret;
139             break;
140         case SSL_ERROR_WANT_READ:
141             iofd->ssl_hs_read = 1;
142             iohandler_update(iofd);
143             iohandler_log(IOLOG_DEBUG, "SSL_write for %s (fd: %d) returned SSL_ERROR_WANT_READ", iohandler_iotype_name(iofd->type), iofd->fd);
144             errno = EAGAIN;
145             return -1;
146             break;
147         case SSL_ERROR_WANT_WRITE:
148             iofd->ssl_hs_write = 1;
149             iohandler_update(iofd);
150             iohandler_log(IOLOG_DEBUG, "SSL_write for %s (fd: %d) returned SSL_ERROR_WANT_WRITE", iohandler_iotype_name(iofd->type), iofd->fd);
151             errno = EAGAIN;
152             return -1;
153             break;
154         default:
155             iohandler_log(IOLOG_ERROR, "SSL_write for %s (fd: %d) failed with ", iohandler_iotype_name(iofd->type), iofd->fd);
156             return -1;
157             break;
158     }
159 #endif
160     return 0;
161 }