]> jfr.im git - solanum.git/blob - librb/src/gnutls.c
check bans and quiets for cmode -n/nonmember PRIVMSG
[solanum.git] / librb / src / gnutls.c
1 /*
2 * libratbox: a library used by ircd-ratbox and other things
3 * gnutls.c: gnutls related code
4 *
5 * Copyright (C) 2007-2008 ircd-ratbox development team
6 * Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 *
23 */
24
25 #include <librb_config.h>
26 #include <rb_lib.h>
27
28 #ifdef HAVE_GNUTLS
29
30 #include <commio-int.h>
31 #include <commio-ssl.h>
32 #include <stdbool.h>
33
34 #include <gnutls/gnutls.h>
35
36 #include <gnutls/abstract.h>
37 #include <gnutls/x509.h>
38
39 #if (GNUTLS_VERSION_MAJOR < 3)
40 # include <gcrypt.h>
41 #else
42 # include <gnutls/crypto.h>
43 #endif
44
45 #include "gnutls_ratbox.h"
46
47 typedef enum
48 {
49 RB_FD_TLS_DIRECTION_IN = 0,
50 RB_FD_TLS_DIRECTION_OUT = 1
51 } rb_fd_tls_direction;
52
53 #define SSL_P(x) *((gnutls_session_t *) ((x)->ssl))
54
55
56
57 // Server side variables
58 static gnutls_certificate_credentials_t server_cert_key;
59 static gnutls_dh_params_t server_dhp;
60
61 // Client side variables
62 #define MAX_CERTS 6
63 static gnutls_x509_crt_t client_cert[MAX_CERTS];
64 static gnutls_x509_privkey_t client_key;
65 static unsigned int client_cert_count;
66
67 // Shared variables
68 static gnutls_priority_t default_priority;
69
70
71
72 struct ssl_connect
73 {
74 CNCB *callback;
75 void *data;
76 int timeout;
77 };
78
79 static const char *rb_ssl_strerror(int);
80 static void rb_ssl_connect_realcb(rb_fde_t *, int, struct ssl_connect *);
81
82
83
84 /*
85 * Internal GNUTLS-specific code
86 */
87
88 /*
89 * We only have one certificate to authenticate with, as both a client and server.
90 *
91 * Unfortunately, GNUTLS tries to be clever, and as client, will attempt to use a certificate that the server will
92 * trust. We usually use self-signed certs, though, so the result of this search is always nothing. Therefore, it
93 * uses no certificate to authenticate as a client. This is undesirable, as it breaks fingerprint authentication;
94 * e.g. the connect::fingerprint on the remote ircd will not match.
95 *
96 * Thus, we use this callback to force GNUTLS to authenticate with our (server) certificate as a client.
97 */
98 static int
99 rb_ssl_cert_auth_cb(gnutls_session_t session,
100 const gnutls_datum_t *const req_ca_rdn, const int req_ca_rdn_len,
101 const gnutls_pk_algorithm_t *const sign_algos, const int sign_algos_len,
102 #if (GNUTLS_VERSION_MAJOR < 3)
103 gnutls_retr_st *const st)
104 #else
105 gnutls_retr2_st *const st)
106 #endif
107 {
108 #if (GNUTLS_VERSION_MAJOR < 3)
109 st->type = GNUTLS_CRT_X509;
110 #else
111 st->cert_type = GNUTLS_CRT_X509;
112 st->key_type = GNUTLS_PRIVKEY_X509;
113 #endif
114
115 st->ncerts = client_cert_count;
116 st->cert.x509 = client_cert;
117 st->key.x509 = client_key;
118 st->deinit_all = 0;
119
120 return 0;
121 }
122
123 static ssize_t
124 rb_sock_net_recv(gnutls_transport_ptr_t context_ptr, void *const buf, const size_t count)
125 {
126 const int fd = rb_get_fd((rb_fde_t *)context_ptr);
127
128 return recv(fd, buf, count, 0);
129 }
130
131 static ssize_t
132 rb_sock_net_xmit(gnutls_transport_ptr_t context_ptr, const void *const buf, const size_t count)
133 {
134 const int fd = rb_get_fd((rb_fde_t *)context_ptr);
135
136 return send(fd, buf, count, 0);
137 }
138
139 static void
140 rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir)
141 {
142 F->ssl = rb_malloc(sizeof(gnutls_session_t));
143
144 if(F->ssl == NULL)
145 {
146 rb_lib_log("%s: rb_malloc: allocation failure", __func__);
147 rb_close(F);
148 return;
149 }
150
151 unsigned int init_flags = 0;
152
153 switch(dir)
154 {
155 case RB_FD_TLS_DIRECTION_IN:
156 init_flags |= GNUTLS_SERVER;
157 break;
158 case RB_FD_TLS_DIRECTION_OUT:
159 init_flags |= GNUTLS_CLIENT;
160 break;
161 }
162
163 gnutls_init((gnutls_session_t *) F->ssl, init_flags);
164 gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key);
165 gnutls_dh_set_prime_bits(SSL_P(F), 2048);
166
167 gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) F);
168 gnutls_transport_set_pull_function(SSL_P(F), rb_sock_net_recv);
169 gnutls_transport_set_push_function(SSL_P(F), rb_sock_net_xmit);
170
171 if (gnutls_priority_set(SSL_P(F), default_priority) != GNUTLS_E_SUCCESS)
172 gnutls_set_default_priority(SSL_P(F));
173
174 if(dir == RB_FD_TLS_DIRECTION_IN)
175 gnutls_certificate_server_set_request(SSL_P(F), GNUTLS_CERT_REQUEST);
176 }
177
178 static void
179 rb_ssl_accept_common(rb_fde_t *const F, void *const data)
180 {
181 lrb_assert(F != NULL);
182 lrb_assert(F->accept != NULL);
183 lrb_assert(F->accept->callback != NULL);
184 lrb_assert(F->ssl != NULL);
185
186 errno = 0;
187
188 const int ret = gnutls_handshake(SSL_P(F));
189 const int err = errno;
190
191 if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err))))
192 {
193 unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE;
194 rb_setselect(F, flags, rb_ssl_accept_common, data);
195 return;
196 }
197
198 // These 2 calls may affect errno, which is why we save it above and restore it below
199 rb_settimeout(F, 0, NULL, NULL);
200 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
201
202 struct acceptdata *const ad = F->accept;
203 F->accept = NULL;
204
205 if(ret == GNUTLS_E_SUCCESS)
206 {
207 F->handshake_count++;
208 ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
209 }
210 else if(ret == GNUTLS_E_INTERRUPTED && err != 0)
211 {
212 errno = err;
213 ad->callback(F, RB_ERROR, NULL, 0, ad->data);
214 }
215 else
216 {
217 errno = EIO;
218 F->ssl_errno = (unsigned long) -ret;
219 ad->callback(F, RB_ERROR_SSL, NULL, 0, ad->data);
220 }
221
222 rb_free(ad);
223 }
224
225 static void
226 rb_ssl_connect_common(rb_fde_t *const F, void *const data)
227 {
228 lrb_assert(F != NULL);
229 lrb_assert(F->ssl != NULL);
230
231 errno = 0;
232
233 const int ret = gnutls_handshake(SSL_P(F));
234 const int err = errno;
235
236 if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err))))
237 {
238 unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE;
239 rb_setselect(F, flags, rb_ssl_connect_common, data);
240 return;
241 }
242
243 // These 2 calls may affect errno, which is why we save it above and restore it below
244 rb_settimeout(F, 0, NULL, NULL);
245 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
246
247 struct ssl_connect *const sconn = data;
248
249 if(ret == GNUTLS_E_SUCCESS)
250 {
251 F->handshake_count++;
252 rb_ssl_connect_realcb(F, RB_OK, sconn);
253 }
254 else if(ret == GNUTLS_E_INTERRUPTED && err != 0)
255 {
256 errno = err;
257 rb_ssl_connect_realcb(F, RB_ERROR, sconn);
258 }
259 else
260 {
261 errno = EIO;
262 F->ssl_errno = (unsigned long) -ret;
263 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
264 }
265 }
266
267 static const char *
268 rb_ssl_strerror(const int err)
269 {
270 return gnutls_strerror(err);
271 }
272
273 static ssize_t
274 rb_ssl_read_or_write(const int r_or_w, rb_fde_t *const F, void *const rbuf, const void *const wbuf, const size_t count)
275 {
276 ssize_t ret;
277
278 errno = 0;
279
280 if(r_or_w == 0)
281 ret = gnutls_record_recv(SSL_P(F), rbuf, count);
282 else
283 ret = gnutls_record_send(SSL_P(F), wbuf, count);
284
285 if(ret >= 0)
286 return ret;
287
288 if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (errno == 0 || rb_ignore_errno(errno))))
289 {
290 if(gnutls_record_get_direction(SSL_P(F)) == 0)
291 return RB_RW_SSL_NEED_READ;
292 else
293 return RB_RW_SSL_NEED_WRITE;
294 }
295
296 if(ret == GNUTLS_E_INTERRUPTED && errno != 0)
297 return RB_RW_IO_ERROR;
298
299 errno = EIO;
300 F->ssl_errno = (unsigned long) -ret;
301 return RB_RW_SSL_ERROR;
302 }
303
304 #if (GNUTLS_VERSION_MAJOR < 3)
305 static void
306 rb_gcry_random_seed(void *const unused)
307 {
308 gcry_fast_random_poll();
309 }
310 #endif
311
312 static void
313 rb_free_datum_t(gnutls_datum_t *const datum)
314 {
315 if(datum == NULL)
316 return;
317
318 rb_free(datum->data);
319 rb_free(datum);
320 }
321
322 static gnutls_datum_t *
323 rb_load_file_into_datum_t(const char *const file)
324 {
325 const int datum_fd = open(file, O_RDONLY);
326 if(datum_fd < 0)
327 return NULL;
328
329 struct stat fileinfo;
330 if(fstat(datum_fd, &fileinfo) != 0)
331 {
332 (void) close(datum_fd);
333 return NULL;
334 }
335
336 const size_t datum_size = (fileinfo.st_size < 131072) ? (size_t) fileinfo.st_size : 131072;
337 if(datum_size == 0)
338 {
339 (void) close(datum_fd);
340 return NULL;
341 }
342
343 gnutls_datum_t *datum;
344 if((datum = rb_malloc(sizeof *datum)) == NULL)
345 {
346 (void) close(datum_fd);
347 return NULL;
348 }
349 if((datum->data = rb_malloc(datum_size + 1)) == NULL)
350 {
351 rb_free(datum);
352 (void) close(datum_fd);
353 return NULL;
354 }
355
356 for(size_t data_read = 0; data_read < datum_size; )
357 {
358 ssize_t ret = read(datum_fd, ((unsigned char *)datum->data) + data_read, datum_size - data_read);
359
360 if(ret <= 0)
361 {
362 rb_free_datum_t(datum);
363 (void) close(datum_fd);
364 return NULL;
365 }
366
367 data_read += (size_t) ret;
368 }
369 (void) close(datum_fd);
370
371 datum->data[datum_size] = '\0';
372 datum->size = (unsigned int) datum_size;
373 return datum;
374 }
375
376 static int
377 make_certfp(gnutls_x509_crt_t cert, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method)
378 {
379 int hashlen;
380 gnutls_digest_algorithm_t md_type;
381
382 bool spki = false;
383
384 switch(method)
385 {
386 case RB_SSL_CERTFP_METH_CERT_SHA1:
387 hashlen = RB_SSL_CERTFP_LEN_SHA1;
388 md_type = GNUTLS_DIG_SHA1;
389 break;
390 case RB_SSL_CERTFP_METH_SPKI_SHA256:
391 spki = true;
392 case RB_SSL_CERTFP_METH_CERT_SHA256:
393 hashlen = RB_SSL_CERTFP_LEN_SHA256;
394 md_type = GNUTLS_DIG_SHA256;
395 break;
396 case RB_SSL_CERTFP_METH_SPKI_SHA512:
397 spki = true;
398 case RB_SSL_CERTFP_METH_CERT_SHA512:
399 hashlen = RB_SSL_CERTFP_LEN_SHA512;
400 md_type = GNUTLS_DIG_SHA512;
401 break;
402 default:
403 return 0;
404 }
405
406 if(! spki)
407 {
408 size_t digest_size = (size_t) hashlen;
409
410 if(gnutls_x509_crt_get_fingerprint(cert, md_type, certfp, &digest_size) != 0)
411 return 0;
412
413 return hashlen;
414 }
415
416 gnutls_pubkey_t pubkey;
417
418 if(gnutls_pubkey_init(&pubkey) != 0)
419 return 0;
420
421 if(gnutls_pubkey_import_x509(pubkey, cert, 0) != 0)
422 {
423 gnutls_pubkey_deinit(pubkey);
424 return 0;
425 }
426
427 unsigned char derkey[262144]; // Should be big enough to hold any SubjectPublicKeyInfo structure
428 size_t derkey_len = sizeof derkey;
429
430 if(gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_DER, derkey, &derkey_len) != 0)
431 {
432 gnutls_pubkey_deinit(pubkey);
433 return 0;
434 }
435
436 gnutls_pubkey_deinit(pubkey);
437
438 if(gnutls_hash_fast(md_type, derkey, derkey_len, certfp) != 0)
439 return 0;
440
441 return hashlen;
442 }
443
444
445
446 /*
447 * External GNUTLS-specific code
448 */
449
450 void
451 rb_ssl_shutdown(rb_fde_t *const F)
452 {
453 if(F == NULL || F->ssl == NULL)
454 return;
455
456 for(int i = 0; i < 4; i++)
457 {
458 int ret = gnutls_bye(SSL_P(F), GNUTLS_SHUT_RDWR);
459
460 if(ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_AGAIN)
461 break;
462 }
463
464 gnutls_deinit(SSL_P(F));
465
466 rb_free(F->ssl);
467 F->ssl = NULL;
468 }
469
470 int
471 rb_init_ssl(void)
472 {
473 int ret;
474
475 if((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS)
476 {
477 rb_lib_log("%s: gnutls_global_init: %s", __func__, rb_ssl_strerror(ret));
478 return 0;
479 }
480
481 #if (GNUTLS_VERSION_MAJOR < 3)
482 rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300);
483 #endif
484
485 return 1;
486 }
487
488 int
489 rb_setup_ssl_server(const char *const certfile, const char *keyfile,
490 const char *const dhfile, const char *cipherlist)
491 {
492 if(certfile == NULL)
493 {
494 rb_lib_log("%s: no certificate file specified", __func__);
495 return 0;
496 }
497
498 if(keyfile == NULL)
499 keyfile = certfile;
500
501 if(cipherlist == NULL)
502 cipherlist = rb_gnutls_default_priority_str;
503
504
505 gnutls_datum_t *const d_cert = rb_load_file_into_datum_t(certfile);
506 if(d_cert == NULL)
507 {
508 rb_lib_log("%s: Error loading certificate: %s", __func__, strerror(errno));
509 return 0;
510 }
511
512 gnutls_datum_t *const d_key = rb_load_file_into_datum_t(keyfile);
513 if(d_key == NULL)
514 {
515 rb_lib_log("%s: Error loading key: %s", __func__, strerror(errno));
516 rb_free_datum_t(d_cert);
517 return 0;
518 }
519
520 int ret;
521
522 if((ret = gnutls_certificate_allocate_credentials(&server_cert_key)) != GNUTLS_E_SUCCESS)
523 {
524 rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__, rb_ssl_strerror(ret));
525 rb_free_datum_t(d_cert);
526 rb_free_datum_t(d_key);
527 return 0;
528 }
529
530 #if (GNUTLS_VERSION_MAJOR < 3)
531 gnutls_certificate_client_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb);
532 #else
533 gnutls_certificate_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb);
534 #endif
535
536 if((ret = gnutls_certificate_set_x509_key_mem(server_cert_key, d_cert, d_key,
537 GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS)
538 {
539 rb_lib_log("%s: gnutls_certificate_set_x509_key_mem: %s", __func__, rb_ssl_strerror(ret));
540 gnutls_certificate_free_credentials(server_cert_key);
541 rb_free_datum_t(d_cert);
542 rb_free_datum_t(d_key);
543 return 0;
544 }
545 if((ret = gnutls_x509_crt_list_import(client_cert, &client_cert_count, d_cert, GNUTLS_X509_FMT_PEM,
546 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED)) < 1)
547 {
548 rb_lib_log("%s: gnutls_x509_crt_list_import: %s", __func__, rb_ssl_strerror(ret));
549 gnutls_certificate_free_credentials(server_cert_key);
550 rb_free_datum_t(d_cert);
551 rb_free_datum_t(d_key);
552 return 0;
553 }
554 client_cert_count = (unsigned int) ret;
555
556 if((ret = gnutls_x509_privkey_init(&client_key)) != GNUTLS_E_SUCCESS)
557 {
558 rb_lib_log("%s: gnutls_x509_privkey_init: %s", __func__, rb_ssl_strerror(ret));
559 gnutls_certificate_free_credentials(server_cert_key);
560 for(unsigned int i = 0; i < client_cert_count; i++)
561 gnutls_x509_crt_deinit(client_cert[i]);
562 rb_free_datum_t(d_cert);
563 rb_free_datum_t(d_key);
564 return 0;
565 }
566 if((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS)
567 {
568 rb_lib_log("%s: gnutls_x509_privkey_import: %s", __func__, rb_ssl_strerror(ret));
569 gnutls_certificate_free_credentials(server_cert_key);
570 for(unsigned int i = 0; i < client_cert_count; i++)
571 gnutls_x509_crt_deinit(client_cert[i]);
572 gnutls_x509_privkey_deinit(client_key);
573 rb_free_datum_t(d_cert);
574 rb_free_datum_t(d_key);
575 return 0;
576 }
577
578 rb_free_datum_t(d_cert);
579 rb_free_datum_t(d_key);
580
581 if(dhfile != NULL)
582 {
583 gnutls_datum_t *const d_dhp = rb_load_file_into_datum_t(dhfile);
584
585 if(d_dhp == NULL)
586 {
587 rb_lib_log("%s: Error parsing DH parameters: %s", __func__, strerror(errno));
588 gnutls_certificate_free_credentials(server_cert_key);
589 for(unsigned int i = 0; i < client_cert_count; i++)
590 gnutls_x509_crt_deinit(client_cert[i]);
591 gnutls_x509_privkey_deinit(client_key);
592 return 0;
593 }
594 if((ret = gnutls_dh_params_init(&server_dhp)) != GNUTLS_E_SUCCESS)
595 {
596 rb_lib_log("%s: Error parsing DH parameters: %s", __func__, rb_ssl_strerror(ret));
597 gnutls_certificate_free_credentials(server_cert_key);
598 for(unsigned int i = 0; i < client_cert_count; i++)
599 gnutls_x509_crt_deinit(client_cert[i]);
600 gnutls_x509_privkey_deinit(client_key);
601 rb_free_datum_t(d_dhp);
602 return 0;
603 }
604 if((ret = gnutls_dh_params_import_pkcs3(server_dhp, d_dhp, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS)
605 {
606 rb_lib_log("%s: Error parsing DH parameters: %s", __func__, rb_ssl_strerror(ret));
607 gnutls_certificate_free_credentials(server_cert_key);
608 for(unsigned int i = 0; i < client_cert_count; i++)
609 gnutls_x509_crt_deinit(client_cert[i]);
610 gnutls_x509_privkey_deinit(client_key);
611 gnutls_dh_params_deinit(server_dhp);
612 rb_free_datum_t(d_dhp);
613 return 0;
614 }
615
616 gnutls_certificate_set_dh_params(server_cert_key, server_dhp);
617 rb_free_datum_t(d_dhp);
618 }
619
620 const char *err = NULL;
621 if((ret = gnutls_priority_init(&default_priority, cipherlist, &err)) != GNUTLS_E_SUCCESS)
622 {
623 rb_lib_log("%s: gnutls_priority_init: %s, error begins at '%s'? -- using defaults instead",
624 __func__, rb_ssl_strerror(ret), err ? err : "<unknown>");
625
626 (void) gnutls_priority_init(&default_priority, NULL, &err);
627 }
628
629 rb_lib_log("%s: TLS configuration successful", __func__);
630 return 1;
631 }
632
633 int
634 rb_init_prng(const char *const path, prng_seed_t seed_type)
635 {
636 #if (GNUTLS_VERSION_MAJOR < 3)
637 gcry_fast_random_poll();
638 rb_lib_log("%s: PRNG initialised", __func__);
639 #else
640 rb_lib_log("%s: Skipping PRNG initialisation; not required by GNUTLS v3+ backend", __func__);
641 #endif
642 return 1;
643 }
644
645 int
646 rb_get_random(void *const buf, const size_t length)
647 {
648 #if (GNUTLS_VERSION_MAJOR < 3)
649 gcry_randomize(buf, length, GCRY_STRONG_RANDOM);
650 #else
651 gnutls_rnd(GNUTLS_RND_KEY, buf, length);
652 #endif
653 return 1;
654 }
655
656 const char *
657 rb_get_ssl_strerror(rb_fde_t *const F)
658 {
659 const int err = (int) F->ssl_errno;
660 return rb_ssl_strerror(-err);
661 }
662
663 int
664 rb_get_ssl_certfp(rb_fde_t *const F, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method)
665 {
666 if(gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509)
667 return 0;
668
669 unsigned int cert_list_size = 0;
670 const gnutls_datum_t *const cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size);
671 if(cert_list == NULL || cert_list_size < 1)
672 return 0;
673
674 gnutls_x509_crt_t peer_cert;
675 if(gnutls_x509_crt_init(&peer_cert) != 0)
676 return 0;
677
678 if(gnutls_x509_crt_import(peer_cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
679 {
680 gnutls_x509_crt_deinit(peer_cert);
681 return 0;
682 }
683
684 const int len = make_certfp(peer_cert, certfp, method);
685
686 gnutls_x509_crt_deinit(peer_cert);
687
688 return len;
689 }
690
691 int
692 rb_get_ssl_certfp_file(const char *const filename, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method)
693 {
694 gnutls_datum_t *const datum_cert = rb_load_file_into_datum_t(filename);
695 if(datum_cert == NULL)
696 return -1;
697
698 gnutls_x509_crt_t cert;
699 if(gnutls_x509_crt_init(&cert) != 0)
700 {
701 rb_free_datum_t(datum_cert);
702 return 0;
703 }
704 if(gnutls_x509_crt_import(cert, datum_cert, GNUTLS_X509_FMT_PEM) < 0)
705 {
706 gnutls_x509_crt_deinit(cert);
707 rb_free_datum_t(datum_cert);
708 return 0;
709 }
710
711 const int len = make_certfp(cert, certfp, method);
712
713 gnutls_x509_crt_deinit(cert);
714 rb_free_datum_t(datum_cert);
715
716 return len;
717 }
718
719 void
720 rb_get_ssl_info(char *const buf, const size_t len)
721 {
722 (void) snprintf(buf, len, "GNUTLS: compiled (v%s), library (v%s)",
723 LIBGNUTLS_VERSION, gnutls_check_version(NULL));
724 }
725
726 const char *
727 rb_ssl_get_cipher(rb_fde_t *const F)
728 {
729 if(F == NULL || F->ssl == NULL)
730 return NULL;
731
732 static char buf[512];
733
734 gnutls_protocol_t version_ptr = gnutls_protocol_get_version(SSL_P(F));
735 gnutls_cipher_algorithm_t cipher_ptr = gnutls_cipher_get(SSL_P(F));
736
737 const char *const version = gnutls_protocol_get_name(version_ptr);
738 const char *const cipher = gnutls_cipher_get_name(cipher_ptr);
739
740 (void) snprintf(buf, sizeof buf, "%s, %s", version, cipher);
741
742 return buf;
743 }
744
745 ssize_t
746 rb_ssl_read(rb_fde_t *const F, void *const buf, const size_t count)
747 {
748 return rb_ssl_read_or_write(0, F, buf, NULL, count);
749 }
750
751 ssize_t
752 rb_ssl_write(rb_fde_t *const F, const void *const buf, const size_t count)
753 {
754 return rb_ssl_read_or_write(1, F, NULL, buf, count);
755 }
756
757
758
759 /*
760 * Internal library-agnostic code
761 */
762
763 static void
764 rb_ssl_connect_realcb(rb_fde_t *const F, const int status, struct ssl_connect *const sconn)
765 {
766 lrb_assert(F != NULL);
767 lrb_assert(F->connect != NULL);
768
769 F->connect->callback = sconn->callback;
770 F->connect->data = sconn->data;
771
772 rb_connect_callback(F, status);
773 rb_free(sconn);
774 }
775
776 static void
777 rb_ssl_timeout_cb(rb_fde_t *const F, void *const data)
778 {
779 lrb_assert(F->accept != NULL);
780 lrb_assert(F->accept->callback != NULL);
781
782 F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
783 }
784
785 static void
786 rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data)
787 {
788 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
789 }
790
791 static void
792 rb_ssl_tryconn(rb_fde_t *const F, const int status, void *const data)
793 {
794 lrb_assert(F != NULL);
795
796 struct ssl_connect *const sconn = data;
797
798 if(status != RB_OK)
799 {
800 rb_ssl_connect_realcb(F, status, sconn);
801 return;
802 }
803
804 F->type |= RB_FD_SSL;
805
806 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
807 rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT);
808 rb_ssl_connect_common(F, sconn);
809 }
810
811
812
813 /*
814 * External library-agnostic code
815 */
816
817 int
818 rb_supports_ssl(void)
819 {
820 return 1;
821 }
822
823 unsigned int
824 rb_ssl_handshake_count(rb_fde_t *const F)
825 {
826 return F->handshake_count;
827 }
828
829 void
830 rb_ssl_clear_handshake_count(rb_fde_t *const F)
831 {
832 F->handshake_count = 0;
833 }
834
835 void
836 rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout)
837 {
838 F->type |= RB_FD_SSL;
839
840 F->accept = rb_malloc(sizeof(struct acceptdata));
841 F->accept->callback = cb;
842 F->accept->data = data;
843 F->accept->addrlen = 0;
844 (void) memset(&F->accept->S, 0x00, sizeof F->accept->S);
845
846 rb_settimeout(F, timeout, rb_ssl_timeout_cb, NULL);
847 rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN);
848 rb_ssl_accept_common(F, NULL);
849 }
850
851 void
852 rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen)
853 {
854 cli_F->type |= RB_FD_SSL;
855
856 cli_F->accept = rb_malloc(sizeof(struct acceptdata));
857 cli_F->accept->callback = srv_F->accept->callback;
858 cli_F->accept->data = srv_F->accept->data;
859 cli_F->accept->addrlen = (rb_socklen_t) addrlen;
860 (void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S);
861 (void) memcpy(&cli_F->accept->S, st, (size_t) addrlen);
862
863 rb_settimeout(cli_F, 10, rb_ssl_timeout_cb, NULL);
864 rb_ssl_init_fd(cli_F, RB_FD_TLS_DIRECTION_IN);
865 rb_ssl_accept_common(cli_F, NULL);
866 }
867
868 int
869 rb_ssl_listen(rb_fde_t *const F, const int backlog, const int defer_accept)
870 {
871 int result = rb_listen(F, backlog, defer_accept);
872
873 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
874
875 return result;
876 }
877
878 void
879 rb_connect_tcp_ssl(rb_fde_t *const F, struct sockaddr *const dest, struct sockaddr *const clocal,
880 CNCB *const callback, void *const data, const int timeout)
881 {
882 if(F == NULL)
883 return;
884
885 struct ssl_connect *const sconn = rb_malloc(sizeof *sconn);
886 sconn->data = data;
887 sconn->callback = callback;
888 sconn->timeout = timeout;
889
890 rb_connect_tcp(F, dest, clocal, rb_ssl_tryconn, sconn, timeout);
891 }
892
893 void
894 rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data, const int timeout)
895 {
896 if(F == NULL)
897 return;
898
899 struct ssl_connect *const sconn = rb_malloc(sizeof *sconn);
900 sconn->data = data;
901 sconn->callback = callback;
902 sconn->timeout = timeout;
903
904 F->connect = rb_malloc(sizeof(struct conndata));
905 F->connect->callback = callback;
906 F->connect->data = data;
907
908 F->type |= RB_FD_SSL;
909
910 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
911 rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT);
912 rb_ssl_connect_common(F, sconn);
913 }
914
915 #endif /* HAVE_GNUTLS */