2 * IRC - Internet Relay Chat, ircd/ssl.openssl.c
3 * Copyright (C) 2015 pk910 (Philipp Kreil)
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)
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.
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.
20 * @brief Implementation of functions for handling ssl connections
24 static struct SSLPendingConections {
25 struct SSLConnection *connection;
26 struct SSLPendingConections *next;
29 enum SSLDataType datatype;
32 struct SSLPendingConections *firstPendingConection = NULL;
33 int ssl_is_initialized = 0;
35 static void ssl_init() {
36 if(ssl_is_initialized)
38 ssl_is_initialized = 1;
40 OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
41 SSL_load_error_strings();
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;
50 SSL_shutdown(connection->session);
51 SSL_free(connection->session);
53 SSL_CTX_free(context);
57 void ssl_free_listener(struct SSLListener *listener) {
58 SSL_CTX_free(listener->context);
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) {
67 lastPending->next = pending->next;
69 firstPendingConection = pending->next;
70 switch(pending->datatype) {
71 case SSLData_Client: {
72 struct Client *cptr = (struct Client *) pending->data;
74 if(FlagHas(&connection->flags, SSLFLAG_INCOMING))
76 else if(!completed_connection(cptr))
77 exit_client_msg(cptr, cptr, &me, "Registration failed.");
79 exit_client_msg(cptr, cptr, &me, "SSL Handshake failed.");
85 lastPending = pending;
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);
94 switch(SSL_get_error(connection->session, ret)) {
96 FlagClr(&connection->flags, SSLFLAG_HANDSHAKE);
97 FlagSet(&connection->flags, SSLFLAG_READY);
99 ssl_handshake_completed(connection, 1);
101 case SSL_ERROR_WANT_READ:
102 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
104 case SSL_ERROR_WANT_WRITE:
105 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
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;
121 if(!ssl_is_initialized)
124 connection->context = SSL_CTX_new(SSLv23_client_method());
125 if(!connection->context) {
126 goto ssl_create_connect_failed;
128 connection->session = SSL_new(connection->context);
129 if(!connection->session) {
130 goto ssl_create_connect_failed;
132 if(!SSL_set_fd(connection->session, fd)) {
133 goto ssl_create_connect_failed;
135 SSL_set_connect_state(connection->session);
136 FlagSet(&connection->flags, SSLFLAG_OUTGOING);
137 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE);
139 pending = malloc(sizeof(*pending));
141 goto ssl_create_connect_failed;
143 pending->connection = connection;
144 pending->next = firstPendingConection;
145 firstPendingConection = pending;
147 pending->data = data;
148 pending->datatype = datatype;
151 ssl_create_connect_failed:
156 void ssl_start_handshake_connect(struct SSLConnection *connection) {
157 ssl_handshake_outgoing(connection);
160 struct SSLListener *ssl_create_listener() {
161 if(!ssl_is_initialized)
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;
170 char *certfile = conf_get_local()->sslcertfile;
171 char *keyfile = conf_get_local()->sslkeyfile;
172 char *cafile = conf_get_local()->sslcafile;
175 goto ssl_create_listener_failed;
181 /* load certificate */
182 if(SSL_CTX_use_certificate_file(listener->context, certfile, SSL_FILETYPE_PEM) <= 0) {
183 goto ssl_create_listener_failed;
186 if(SSL_CTX_use_PrivateKey_file(listener->context, keyfile, SSL_FILETYPE_PEM) <= 0) {
187 goto ssl_create_listener_failed;
189 /* check certificate and keyfile */
190 if(!SSL_CTX_check_private_key(listener->context)) {
191 goto ssl_create_listener_failed;
194 if(cafile && cafile[0] && SSL_CTX_load_verify_locations(listener->context, cafile, NULL) <= 0) {
195 goto ssl_create_listener_failed;
197 FlagSet(&listener->flags, SSLFLAG_READY);
199 ssl_create_listener_failed:
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)) {
210 FlagClr(&connection->flags, SSLFLAG_HANDSHAKE);
211 FlagSet(&connection->flags, SSLFLAG_READY);
213 ssl_handshake_completed(connection, 1);
215 case SSL_ERROR_WANT_READ:
216 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
218 case SSL_ERROR_WANT_WRITE:
219 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
224 ssl_handshake_completed(connection, 0);
230 struct SSLConnection *ssl_start_handshake_listener(struct SSLListener *listener, int fd, void *data, enum SSLDataType datatype) {
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;
239 if(!SSL_set_fd(connection->session, fd)) {
240 goto ssl_start_handshake_listener_failed;
242 FlagSet(&connection->flags, SSLFLAG_INCOMING);
243 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE);
244 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
246 pending = malloc(sizeof(*pending));
248 goto ssl_start_handshake_listener_failed;
250 pending->connection = connection;
251 pending->next = firstPendingConection;
252 firstPendingConection = pending;
254 pending->data = data;
255 pending->datatype = datatype;
257 ssl_handshake_incoming(connection);
259 ssl_start_handshake_listener_failed:
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);
270 if(FlagHas(&connection->flags, SSLFLAG_OUTGOING)) {
271 ssl_handshake_outgoing(connection);
276 *len = SSL_read(connection->session, buf, buflen);
277 FlagClr(&connection->flags, SSLFLAG_HANDSHAKE_R);
278 int err = SSL_get_error(connection->session, *len);
282 case SSL_ERROR_ZERO_RETURN:
284 case SSL_ERROR_WANT_READ:
285 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
287 case SSL_ERROR_WANT_WRITE:
288 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
290 case SSL_ERROR_SYSCALL:
297 static ssize_t ssl_writev(SSL *ssl, const struct iovec *vector, int count) {
300 size_t bytes, to_copy;
303 /* Find the total number of bytes to be written. */
305 for (i = 0; i < count; ++i)
306 bytes += vector[i].iov_len;
308 /* Allocate a temporary buffer to hold the data. */
309 buffer = (char *) alloca (bytes);
311 /* Copy the data into 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);
322 return SSL_write(ssl, buffer, bytes);
325 IOResult ssl_send_encrypt_plain(struct SSLConnection *connection, char* buf, int len) {
326 return SSL_write(connection->session, buf, len);
329 IOResult ssl_send_encrypt(struct SSLConnection *connection, struct MsgQ* buf, unsigned int *count_in, unsigned int *count_out) {
332 struct iovec iov[IOV_MAX];
335 assert(0 != count_in);
336 assert(0 != count_out);
339 count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
340 res = ssl_writev(connection->session, iov, count);
342 switch(SSL_get_error(connection->session, res)) {
344 case SSL_ERROR_ZERO_RETURN:
345 *count_out = (unsigned) res;
347 case SSL_ERROR_WANT_READ:
348 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_R);
350 case SSL_ERROR_WANT_WRITE:
351 FlagSet(&connection->flags, SSLFLAG_HANDSHAKE_W);
359 int ssl_connection_flush(struct SSLConnection *connection) {
361 if(ssl_handshake(connection)) {
362 if(FlagHas(&connection->flags, SSLFLAG_INCOMING)) {
363 return ssl_handshake_incoming(connection);
365 if(FlagHas(&connection->flags, SSLFLAG_OUTGOING)) {
366 return ssl_handshake_outgoing(connection);
370 struct SSLPendingConections *curr, *last = NULL, *next;
371 for(curr = firstPendingConection; curr; curr = next) {
373 if(!ssl_connection_flush(curr->connection)) {
374 // connection is already in auth process here, curr is freed!
383 const char* ssl_get_cipher(struct SSLConnection *connection) {
386 static char buf[400];
392 strcpy(buf, SSL_get_version(connection->session));
394 strcat(buf, SSL_get_cipher(connection->session));
395 c = SSL_get_current_cipher(connection->session);
396 SSL_CIPHER_get_bits(c, &bits);
398 ircd_snprintf(0, buf2, sizeof(buf2), "%d", bits);