Update Red Hat Copyright Notices
[nbdkit.git] / server / crypto.c
blob56f48efb491ff3b843c5c7db40c8cf1e8f3df3cf
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <stdint.h>
39 #include <stdbool.h>
40 #include <inttypes.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <sys/types.h>
46 #include <assert.h>
48 #include "cleanup.h"
49 #include "internal.h"
50 #include "realpath.h"
51 #include "strndup.h"
53 #ifdef HAVE_GNUTLS
55 #include <gnutls/gnutls.h>
56 #include <gnutls/x509.h>
58 #if defined HAVE_GNUTLS_TRANSPORT_IS_KTLS_ENABLED && \
59 defined HAVE_GNUTLS_SOCKET_H
60 #define TRY_KTLS 1
61 #else
62 #define TRY_KTLS 0
63 #endif
64 #if TRY_KTLS
65 #include <gnutls/socket.h>
66 #endif
68 static int crypto_auth;
69 #define CRYPTO_AUTH_CERTIFICATES 1
70 #define CRYPTO_AUTH_PSK 2
72 static gnutls_certificate_credentials_t x509_creds;
73 static gnutls_psk_server_credentials_t psk_creds;
75 static void print_gnutls_error (int err, const char *fs, ...)
76 ATTRIBUTE_FORMAT_PRINTF (2, 3);
78 static void
79 print_gnutls_error (int err, const char *fs, ...)
81 va_list args;
83 fprintf (stderr, "%s: GnuTLS error: ", program_name);
85 va_start (args, fs);
86 vfprintf (stderr, fs, args);
87 va_end (args);
89 fprintf (stderr, ": %s\n", gnutls_strerror (err));
92 /* Try to load certificates from 'path'. Returns true if successful.
93 * If it's not a certicate directory it returns false. Exits on
94 * other errors.
96 static int
97 load_certificates (const char *path)
99 CLEANUP_FREE char *ca_cert_filename = NULL;
100 CLEANUP_FREE char *server_cert_filename = NULL;
101 CLEANUP_FREE char *server_key_filename = NULL;
102 CLEANUP_FREE char *ca_crl_filename = NULL;
103 int err;
105 if (asprintf (&ca_cert_filename, "%s/ca-cert.pem", path) == -1) {
106 perror ("asprintf");
107 exit (EXIT_FAILURE);
109 if (asprintf (&server_cert_filename, "%s/server-cert.pem", path) == -1) {
110 perror ("asprintf");
111 exit (EXIT_FAILURE);
113 if (asprintf (&server_key_filename, "%s/server-key.pem", path) == -1) {
114 perror ("asprintf");
115 exit (EXIT_FAILURE);
117 if (asprintf (&ca_crl_filename, "%s/ca-crl.pem", path) == -1) {
118 perror ("asprintf");
119 exit (EXIT_FAILURE);
122 /* Our test for a certificate directory is that ca-cert.pem,
123 * server-cert.pem and server-key.pem must all exist in the path.
125 if (access (ca_cert_filename, R_OK) == -1)
126 return 0;
127 if (access (server_cert_filename, R_OK) == -1)
128 return 0;
129 if (access (server_key_filename, R_OK) == -1)
130 return 0;
132 /* Any problem past here is a hard error. */
134 err = gnutls_certificate_allocate_credentials (&x509_creds);
135 if (err < 0) {
136 print_gnutls_error (err, "allocating credentials");
137 exit (EXIT_FAILURE);
139 err = gnutls_certificate_set_x509_trust_file (x509_creds, ca_cert_filename,
140 GNUTLS_X509_FMT_PEM);
141 if (err < 0) {
142 print_gnutls_error (err, "loading %s", ca_cert_filename);
143 exit (EXIT_FAILURE);
146 if (access (ca_crl_filename, R_OK) == 0) {
147 err = gnutls_certificate_set_x509_crl_file (x509_creds, ca_crl_filename,
148 GNUTLS_X509_FMT_PEM);
149 if (err < 0) {
150 print_gnutls_error (err, "loading %s", ca_crl_filename);
151 exit (EXIT_FAILURE);
155 err = gnutls_certificate_set_x509_key_file (x509_creds,
156 server_cert_filename,
157 server_key_filename,
158 GNUTLS_X509_FMT_PEM);
159 if (err < 0) {
160 print_gnutls_error (err, "loading server certificate and key (%s, %s)",
161 server_cert_filename, server_key_filename);
162 exit (EXIT_FAILURE);
165 debug ("successfully loaded TLS certificates from %s", path);
166 return 1;
169 static int
170 start_certificates (void)
172 /* Try to locate the certificates directory and load them. */
173 if (tls_certificates_dir == NULL) {
174 const char *home;
175 CLEANUP_FREE char *path = NULL;
177 #ifndef WIN32
178 #define RUNNING_AS_NON_ROOT_FOR_CERTIFICATES_DIR (geteuid () != 0)
179 #else
180 #define RUNNING_AS_NON_ROOT_FOR_CERTIFICATES_DIR 0
181 #endif
182 if (RUNNING_AS_NON_ROOT_FOR_CERTIFICATES_DIR) {
183 home = getenv ("HOME");
184 if (home) {
185 if (asprintf (&path, "%s/.pki/%s", home, PACKAGE_NAME) == -1) {
186 perror ("asprintf");
187 exit (EXIT_FAILURE);
189 if (load_certificates (path))
190 goto found_certificates;
191 free (path);
192 if (asprintf (&path, "%s/.config/pki/%s", home, PACKAGE_NAME) == -1) {
193 perror ("asprintf");
194 exit (EXIT_FAILURE);
196 if (load_certificates (path))
197 goto found_certificates;
200 else { /* geteuid () == 0 */
201 if (load_certificates (root_tls_certificates_dir))
202 goto found_certificates;
205 else {
206 if (load_certificates (tls_certificates_dir))
207 goto found_certificates;
209 return -1;
211 found_certificates:
212 #ifdef HAVE_GNUTLS_CERTIFICATE_SET_KNOWN_DH_PARAMS
213 gnutls_certificate_set_known_dh_params (x509_creds, GNUTLS_SEC_PARAM_MEDIUM);
214 #endif
215 return 0;
218 static int
219 start_psk (void)
221 int err;
222 CLEANUP_FREE char *abs_psk_file = NULL;
224 /* Make sure the path to the PSK file is absolute. */
225 abs_psk_file = realpath (tls_psk, NULL);
226 if (abs_psk_file == NULL) {
227 perror (tls_psk);
228 exit (EXIT_FAILURE);
231 err = gnutls_psk_allocate_server_credentials (&psk_creds);
232 if (err < 0) {
233 print_gnutls_error (err, "allocating PSK credentials");
234 exit (EXIT_FAILURE);
237 /* Note that this function makes a copy of the string.
238 * CLEANUP_FREE macro above will free abs_psk_file when
239 * we return, but this is safe.
241 gnutls_psk_set_server_credentials_file (psk_creds, abs_psk_file);
243 return 0;
246 /* Initialize crypto. This also handles the command line parameters
247 * and loading the server certificate.
249 void
250 crypto_init (bool tls_set_on_cli)
252 int err, r;
253 const char *what;
255 err = gnutls_global_init ();
256 if (err < 0) {
257 print_gnutls_error (err, "initializing GnuTLS");
258 exit (EXIT_FAILURE);
261 if (tls == 0) /* --tls=off */
262 return;
264 /* --tls-psk overrides certificates. */
265 if (tls_psk != NULL) {
266 what = "Pre-Shared Keys (PSK)";
267 r = start_psk ();
268 if (r == 0)
269 crypto_auth = CRYPTO_AUTH_PSK;
271 else {
272 what = "X.509 certificates";
273 r = start_certificates ();
274 if (r == 0)
275 crypto_auth = CRYPTO_AUTH_CERTIFICATES;
278 if (r == 0) {
279 debug ("TLS enabled using: %s", what);
280 return;
283 /* If we get here, we didn't manage to load the PSK file /
284 * certificates. If --tls=require was given on the command line
285 * then that's a problem.
287 if (tls == 2) { /* --tls=require */
288 fprintf (stderr,
289 "%s: --tls=require but could not load TLS certificates.\n"
290 "Try setting ‘--tls-certificates=/path/to/certificates’ or read\n"
291 "the \"TLS\" section in nbdkit(1).\n",
292 program_name);
293 exit (EXIT_FAILURE);
296 /* If --tls=on was given on the command line, warn before we turn
297 * TLS off.
299 if (tls == 1 && tls_set_on_cli) { /* explicit --tls=on */
300 fprintf (stderr,
301 "%s: warning: --tls=on but could not load TLS certificates.\n"
302 "TLS will be disabled and TLS connections will be rejected.\n"
303 "Try setting ‘--tls-certificates=/path/to/certificates’ or read\n"
304 "the \"TLS\" section in nbdkit(1).\n",
305 program_name);
308 tls = 0;
309 debug ("TLS disabled: could not load TLS certificates");
312 void
313 crypto_free (void)
315 if (tls > 0) {
316 switch (crypto_auth) {
317 case CRYPTO_AUTH_CERTIFICATES:
318 gnutls_certificate_free_credentials (x509_creds);
319 break;
320 case CRYPTO_AUTH_PSK:
321 gnutls_psk_free_server_credentials (psk_creds);
322 break;
326 gnutls_global_deinit ();
329 /* Read buffer from GnuTLS and either succeed completely
330 * (returns > 0), read an EOF (returns 0), or fail (returns -1).
332 static int
333 crypto_recv (void *vbuf, size_t len)
335 GET_CONN;
336 gnutls_session_t session = conn->crypto_session;
337 char *buf = vbuf;
338 ssize_t r;
339 bool first_read = true;
341 assert (session != NULL);
343 while (len > 0) {
344 r = gnutls_record_recv (session, buf, len);
345 if (r < 0) {
346 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
347 continue;
348 nbdkit_error ("gnutls_record_recv: %s", gnutls_strerror (r));
349 errno = EIO;
350 return -1;
352 if (r == 0) {
353 if (first_read)
354 return 0;
355 /* Partial record read. This is an error. */
356 errno = EBADMSG;
357 return -1;
359 first_read = false;
360 buf += r;
361 len -= r;
364 return 1;
367 /* If this send()'s length is so large that it is going to require
368 * multiple TCP segments anyway, there's no need to try and merge it
369 * with any corked data from a previous send that used SEND_MORE.
371 #define MAX_SEND_MORE_LEN (64 * 1024)
373 /* Write buffer to GnuTLS and either succeed completely
374 * (returns 0) or fail (returns -1). flags is ignored for now.
376 static int
377 crypto_send (const void *vbuf, size_t len, int flags)
379 GET_CONN;
380 gnutls_session_t session = conn->crypto_session;
381 const char *buf = vbuf;
382 ssize_t r;
384 assert (session != NULL);
386 if (len + gnutls_record_check_corked (session) > MAX_SEND_MORE_LEN) {
387 if (gnutls_record_uncork (session, GNUTLS_RECORD_WAIT) < 0)
388 return -1;
390 else if (flags & SEND_MORE)
391 gnutls_record_cork (session);
393 while (len > 0) {
394 r = gnutls_record_send (session, buf, len);
395 if (r < 0) {
396 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
397 continue;
398 return -1;
400 buf += r;
401 len -= r;
404 if (!(flags & SEND_MORE) &&
405 gnutls_record_uncork (session, GNUTLS_RECORD_WAIT) < 0)
406 return -1;
408 return 0;
411 /* There's no place in the NBD protocol to send back errors from
412 * close, so this function ignores errors.
414 static void
415 crypto_close (int how)
417 GET_CONN;
418 gnutls_session_t session = conn->crypto_session;
419 int sockin, sockout;
421 assert (session != NULL);
423 if (how == SHUT_WR)
424 gnutls_bye (session, GNUTLS_SHUT_WR);
425 else {
426 gnutls_transport_get_int2 (session, &sockin, &sockout);
428 gnutls_bye (session, GNUTLS_SHUT_RDWR);
430 if (sockin >= 0)
431 closesocket (sockin);
432 if (sockout >= 0 && sockin != sockout)
433 closesocket (sockout);
435 gnutls_deinit (session);
436 conn->crypto_session = NULL;
440 #ifdef WIN32
441 /* Push/pull functions. Only required for Windows, because on Unix we
442 * can use the default send(2) and recv(2). Note these are actually
443 * calling the wrappers win_send and win_recv in windows-compat.h
445 static ssize_t
446 push (gnutls_transport_ptr_t ptr, const void *buf, size_t n)
448 ssize_t r;
450 r = send ((intptr_t) ptr, buf, n, 0);
451 /* XXX call gnutls_transport_set_errno here */
452 return r;
455 static ssize_t
456 pull (gnutls_transport_ptr_t ptr, void *buf, size_t n)
458 ssize_t r;
460 r = recv ((intptr_t) ptr, buf, n, 0);
461 /* XXX call gnutls_transport_set_errno here */
462 return r;
465 static int
466 pull_timeout (gnutls_transport_ptr_t ptr, unsigned ms)
468 #if 0
469 /* XXX This is what you're supposed to do, but I couldn't get it to
470 * work.
472 return gnutls_system_recv_timeout (ptr, ms);
473 #endif
474 return 1;
476 #endif /* WIN32 */
478 /* Turn GnuTLS debug messages into nbdkit debug messages
479 * when nbdkit -D nbdkit.tls.log > 0
481 NBDKIT_DLL_PUBLIC int nbdkit_debug_tls_log = 0;
483 static void
484 tls_log (int level, const char *msg)
486 size_t len;
487 CLEANUP_FREE char *copy = NULL;
489 /* Strip trailing \n added by GnuTLS. */
490 len = strlen (msg);
491 if (len > 0 && msg[len-1] == '\n') {
492 copy = strndup (msg, len-1);
493 msg = copy;
496 debug ("gnutls: %d: %s", level, msg);
499 /* Print additional information about the session using
500 * nbdkit -D nbdkit.tls.session=1
502 * https://gnutls.org/manual/html_node/Obtaining-session-information.html
504 NBDKIT_DLL_PUBLIC int nbdkit_debug_tls_session = 0;
506 static void
507 debug_x590_cert (gnutls_session_t session)
509 const gnutls_datum_t *cert_list;
510 unsigned int i, cert_list_size = 0;
512 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
513 if (cert_list == NULL) {
514 /* Note unless you use --tls-verify-peer you will always see the
515 * following message.
517 debug ("TLS: no peer certificates found");
518 return;
521 debug ("TLS: peer provided %u certificate(s)", cert_list_size);
522 for (i = 0; i < cert_list_size; ++i) {
523 int ret;
524 gnutls_x509_crt_t cert;
525 gnutls_datum_t cinfo;
527 /* This is for debugging; best-effort is okay */
528 ret = gnutls_x509_crt_init (&cert);
529 if (ret != 0)
530 continue;
531 ret = gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER);
532 if (ret != 0) {
533 gnutls_x509_crt_deinit (cert);
534 continue;
537 ret = gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo);
538 if (ret == 0) {
539 debug ("TLS: %s", cinfo.data);
540 gnutls_free (cinfo.data);
543 gnutls_x509_crt_deinit (cert);
547 static void
548 debug_session (gnutls_session_t session)
550 gnutls_credentials_type_t cred;
551 gnutls_kx_algorithm_t kx;
552 bool dhe = false, ecdh = false;
553 int grp;
554 const char *desc, *username, *hint;
555 #if TRY_KTLS
556 gnutls_transport_ktls_enable_flags_t ktls_enabled;
557 #endif
559 if (nbdkit_debug_tls_session <= 0)
560 return;
562 desc = gnutls_session_get_desc (session);
563 if (desc) debug ("TLS session: %s", desc);
565 #if TRY_KTLS
566 ktls_enabled = gnutls_transport_is_ktls_enabled (session);
567 switch (ktls_enabled) {
568 case GNUTLS_KTLS_RECV:
569 debug ("TLS: kTLS enabled for receive only"); break;
570 case GNUTLS_KTLS_SEND:
571 debug ("TLS: kTLS enabled for send only"); break;
572 case GNUTLS_KTLS_DUPLEX:
573 debug ("TLS: kTLS enabled full duplex"); break;
574 default:
575 if ((int) ktls_enabled == 0)
576 debug ("TLS: kTLS disabled");
577 else
578 debug ("TLS: kTLS enabled unknown setting: %d", (int) ktls_enabled);
580 #endif
582 kx = gnutls_kx_get (session);
583 cred = gnutls_auth_get_type (session);
584 switch (cred) {
585 case GNUTLS_CRD_SRP:
586 debug ("TLS: authentication: SRP (Secure Remote Password)");
587 #ifdef HAVE_GNUTLS_SRP_SERVER_GET_USERNAME
588 username = gnutls_srp_server_get_username (session);
589 #else
590 username = NULL;
591 #endif
592 if (username)
593 debug ("TLS: SRP session username: %s", username);
594 break;
595 case GNUTLS_CRD_PSK:
596 debug ("TLS: authentication: PSK (Pre-Shared Key)");
597 hint = gnutls_psk_client_get_hint (session);
598 if (hint)
599 debug ("TLS: PSK hint: %s", hint);
600 username = gnutls_psk_server_get_username (session);
601 if (username)
602 debug ("TLS: PSK username: %s", username);
603 if (kx == GNUTLS_KX_ECDHE_PSK)
604 ecdh = true;
605 else if (kx == GNUTLS_KX_DHE_PSK)
606 dhe = true;
607 break;
608 case GNUTLS_CRD_ANON:
609 debug ("TLS: authentication: anonymous");
610 if (kx == GNUTLS_KX_ANON_ECDH)
611 ecdh = true;
612 else if (kx == GNUTLS_KX_ANON_DH)
613 dhe = true;
614 break;
615 case GNUTLS_CRD_CERTIFICATE:
616 debug ("TLS: authentication: certificate");
617 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
618 debug_x590_cert (session);
619 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS)
620 dhe = true;
621 else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA)
622 ecdh = true;
623 break;
624 default:
625 debug ("TLS: authentication: unknown (%d)", (int) cred);
628 #ifdef HAVE_GNUTLS_GROUP_GET
629 grp = gnutls_group_get (session);
630 #else
631 grp = 0;
632 #endif
633 if (grp) {
634 debug ("TLS: negotiated group: "
635 #ifdef HAVE_GNUTLS_GROUP_GET_NAME
636 "%s", gnutls_group_get_name (grp));
637 #else
638 "%d", grp);
639 #endif
641 else {
642 if (ecdh)
643 debug ("TLS: ephemeral ECDH using curve %s",
644 gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session)));
645 else if (dhe)
646 debug ("TLS: ephemeral DH using prime of %d bits",
647 gnutls_dh_get_prime_bits (session));
651 /* Upgrade an existing connection to TLS. Also this should do access
652 * control if enabled. The protocol code ensures this function can
653 * only be called once per connection.
656 crypto_negotiate_tls (int sockin, int sockout)
658 GET_CONN;
659 gnutls_session_t session;
660 CLEANUP_FREE char *priority = NULL;
661 int err;
663 /* Create the GnuTLS session. */
664 err = gnutls_init (&session, GNUTLS_SERVER);
665 if (err < 0) {
666 nbdkit_error ("gnutls_init: %s", gnutls_strerror (err));
667 return -1;
670 if (nbdkit_debug_tls_log > 0)
671 gnutls_global_set_log_level (nbdkit_debug_tls_log);
672 gnutls_global_set_log_function (tls_log);
674 switch (crypto_auth) {
675 case CRYPTO_AUTH_CERTIFICATES:
676 /* Associate the session with the server credentials (key, cert). */
677 err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE,
678 x509_creds);
679 if (err < 0) {
680 nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err));
681 goto error;
684 /* If verify peer is enabled, tell GnuTLS to request the client
685 * certificates. (Note the default is to not request or verify
686 * certificates).
688 if (tls_verify_peer) {
689 #ifdef HAVE_GNUTLS_SESSION_SET_VERIFY_CERT
690 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
691 gnutls_session_set_verify_cert (session, NULL, 0);
692 #else
693 abort (); /* Checked when we set the flag in main() */
694 #endif
697 priority = strdup (TLS_PRIORITY);
698 if (priority == NULL) {
699 nbdkit_error ("strdup: %m");
700 goto error;
702 break;
704 case CRYPTO_AUTH_PSK:
705 /* Associate the session with the server PSK credentials. */
706 err = gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_creds);
707 if (err < 0) {
708 nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err));
709 goto error;
712 if (asprintf (&priority,
713 "%s:+ECDHE-PSK:+DHE-PSK:+PSK", TLS_PRIORITY) == -1) {
714 nbdkit_error ("asprintf: %m");
715 goto error;
717 break;
719 default:
720 abort ();
723 assert (priority != NULL);
724 err = gnutls_priority_set_direct (session, priority, NULL);
725 if (err < 0) {
726 nbdkit_error ("failed to set TLS session priority to %s: %s",
727 priority, gnutls_strerror (err));
728 goto error;
731 /* Set up GnuTLS so it reads and writes on the raw sockets. */
732 gnutls_transport_set_int2 (session, sockin, sockout);
733 #ifdef WIN32
734 gnutls_transport_set_push_function (session, push);
735 gnutls_transport_set_pull_function (session, pull);
736 gnutls_transport_set_pull_timeout_function (session, pull_timeout);
737 #endif
739 /* Perform the handshake. */
740 debug ("starting TLS handshake");
741 gnutls_handshake_set_timeout (session,
742 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
744 do {
745 err = gnutls_handshake (session);
746 } while (err < 0 && gnutls_error_is_fatal (err) == 0);
747 if (err < 0) {
748 gnutls_handshake_description_t in, out;
750 /* Get some additional debug information about where in the
751 * handshake protocol it failed. You have to look up these codes in
752 * <gnutls/gnutls.h>.
754 in = gnutls_handshake_get_last_in (session);
755 out = gnutls_handshake_get_last_out (session);
756 nbdkit_error ("gnutls_handshake: %s (%d/%d)",
757 gnutls_strerror (err), (int) in, (int) out);
758 goto error;
760 debug ("TLS handshake completed");
761 debug_session (session);
763 /* Set up the connection recv/send/close functions so they call
764 * GnuTLS wrappers instead.
766 conn->crypto_session = session;
767 conn->recv = crypto_recv;
768 conn->send = crypto_send;
769 conn->close = crypto_close;
770 return 0;
772 error:
773 gnutls_deinit (session);
774 return -1;
777 #else /* !HAVE_GNUTLS */
779 /* GnuTLS was not available at compile time. These are stub versions
780 * of the above functions which either do nothing or report errors as
781 * appropriate.
784 void
785 crypto_init (bool tls_set_on_cli)
787 if (tls > 0) {
788 fprintf (stderr,
789 "%s: TLS cannot be enabled because "
790 "this binary was compiled without GnuTLS.\n",
791 program_name);
792 exit (EXIT_FAILURE);
795 tls = 0;
796 debug ("TLS disabled: nbdkit was not compiled with GnuTLS support");
799 void
800 crypto_free (void)
802 /* nothing */
806 crypto_negotiate_tls (int sockin, int sockout)
808 /* Should never be called because tls == 0. */
809 abort ();
812 #endif /* !HAVE_GNUTLS */