vddk: Document that 8.0.0 has now been tested
[nbdkit.git] / server / crypto.c
blob72486bf81aeec4fdf76efd90afb8f7c841fe8e0f
1 /* nbdkit
2 * Copyright (C) 2017-2022 Red Hat Inc.
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 nbdkit_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 nbdkit_debug ("TLS: no peer certificates found");
518 return;
521 nbdkit_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 nbdkit_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) nbdkit_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 nbdkit_debug ("TLS: kTLS enabled for receive only"); break;
570 case GNUTLS_KTLS_SEND:
571 nbdkit_debug ("TLS: kTLS enabled for send only"); break;
572 case GNUTLS_KTLS_DUPLEX:
573 nbdkit_debug ("TLS: kTLS enabled full duplex"); break;
574 default:
575 if ((int) ktls_enabled == 0)
576 nbdkit_debug ("TLS: kTLS disabled");
577 else
578 nbdkit_debug ("TLS: kTLS enabled unknown setting: %d",
579 (int) ktls_enabled);
581 #endif
583 kx = gnutls_kx_get (session);
584 cred = gnutls_auth_get_type (session);
585 switch (cred) {
586 case GNUTLS_CRD_SRP:
587 nbdkit_debug ("TLS: authentication: SRP (Secure Remote Password)");
588 #ifdef HAVE_GNUTLS_SRP_SERVER_GET_USERNAME
589 username = gnutls_srp_server_get_username (session);
590 #else
591 username = NULL;
592 #endif
593 if (username)
594 nbdkit_debug ("TLS: SRP session username: %s", username);
595 break;
596 case GNUTLS_CRD_PSK:
597 nbdkit_debug ("TLS: authentication: PSK (Pre-Shared Key)");
598 hint = gnutls_psk_client_get_hint (session);
599 if (hint)
600 nbdkit_debug ("TLS: PSK hint: %s", hint);
601 username = gnutls_psk_server_get_username (session);
602 if (username)
603 nbdkit_debug ("TLS: PSK username: %s", username);
604 if (kx == GNUTLS_KX_ECDHE_PSK)
605 ecdh = true;
606 else if (kx == GNUTLS_KX_DHE_PSK)
607 dhe = true;
608 break;
609 case GNUTLS_CRD_ANON:
610 nbdkit_debug ("TLS: authentication: anonymous");
611 if (kx == GNUTLS_KX_ANON_ECDH)
612 ecdh = true;
613 else if (kx == GNUTLS_KX_ANON_DH)
614 dhe = true;
615 break;
616 case GNUTLS_CRD_CERTIFICATE:
617 nbdkit_debug ("TLS: authentication: certificate");
618 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
619 debug_x590_cert (session);
620 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS)
621 dhe = true;
622 else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA)
623 ecdh = true;
624 break;
625 default:
626 nbdkit_debug ("TLS: authentication: unknown (%d)", (int) cred);
629 #ifdef HAVE_GNUTLS_GROUP_GET
630 grp = gnutls_group_get (session);
631 #else
632 grp = 0;
633 #endif
634 if (grp) {
635 nbdkit_debug ("TLS: negotiated group: "
636 #ifdef HAVE_GNUTLS_GROUP_GET_NAME
637 "%s", gnutls_group_get_name (grp));
638 #else
639 "%d", grp);
640 #endif
642 else {
643 if (ecdh)
644 nbdkit_debug ("TLS: ephemeral ECDH using curve %s",
645 gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session)));
646 else if (dhe)
647 nbdkit_debug ("TLS: ephemeral DH using prime of %d bits",
648 gnutls_dh_get_prime_bits (session));
652 /* Upgrade an existing connection to TLS. Also this should do access
653 * control if enabled. The protocol code ensures this function can
654 * only be called once per connection.
657 crypto_negotiate_tls (int sockin, int sockout)
659 GET_CONN;
660 gnutls_session_t session;
661 CLEANUP_FREE char *priority = NULL;
662 int err;
664 /* Create the GnuTLS session. */
665 err = gnutls_init (&session, GNUTLS_SERVER);
666 if (err < 0) {
667 nbdkit_error ("gnutls_init: %s", gnutls_strerror (err));
668 return -1;
671 if (nbdkit_debug_tls_log > 0)
672 gnutls_global_set_log_level (nbdkit_debug_tls_log);
673 gnutls_global_set_log_function (tls_log);
675 switch (crypto_auth) {
676 case CRYPTO_AUTH_CERTIFICATES:
677 /* Associate the session with the server credentials (key, cert). */
678 err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE,
679 x509_creds);
680 if (err < 0) {
681 nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err));
682 goto error;
685 /* If verify peer is enabled, tell GnuTLS to request the client
686 * certificates. (Note the default is to not request or verify
687 * certificates).
689 if (tls_verify_peer) {
690 #ifdef HAVE_GNUTLS_SESSION_SET_VERIFY_CERT
691 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
692 gnutls_session_set_verify_cert (session, NULL, 0);
693 #else
694 abort (); /* Checked when we set the flag in main() */
695 #endif
698 priority = strdup (TLS_PRIORITY);
699 if (priority == NULL) {
700 nbdkit_error ("strdup: %m");
701 goto error;
703 break;
705 case CRYPTO_AUTH_PSK:
706 /* Associate the session with the server PSK credentials. */
707 err = gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_creds);
708 if (err < 0) {
709 nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err));
710 goto error;
713 if (asprintf (&priority,
714 "%s:+ECDHE-PSK:+DHE-PSK:+PSK", TLS_PRIORITY) == -1) {
715 nbdkit_error ("asprintf: %m");
716 goto error;
718 break;
720 default:
721 abort ();
724 assert (priority != NULL);
725 err = gnutls_priority_set_direct (session, priority, NULL);
726 if (err < 0) {
727 nbdkit_error ("failed to set TLS session priority to %s: %s",
728 priority, gnutls_strerror (err));
729 goto error;
732 /* Set up GnuTLS so it reads and writes on the raw sockets. */
733 gnutls_transport_set_int2 (session, sockin, sockout);
734 #ifdef WIN32
735 gnutls_transport_set_push_function (session, push);
736 gnutls_transport_set_pull_function (session, pull);
737 gnutls_transport_set_pull_timeout_function (session, pull_timeout);
738 #endif
740 /* Perform the handshake. */
741 debug ("starting TLS handshake");
742 gnutls_handshake_set_timeout (session,
743 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
745 do {
746 err = gnutls_handshake (session);
747 } while (err < 0 && gnutls_error_is_fatal (err) == 0);
748 if (err < 0) {
749 gnutls_handshake_description_t in, out;
751 /* Get some additional debug information about where in the
752 * handshake protocol it failed. You have to look up these codes in
753 * <gnutls/gnutls.h>.
755 in = gnutls_handshake_get_last_in (session);
756 out = gnutls_handshake_get_last_out (session);
757 nbdkit_error ("gnutls_handshake: %s (%d/%d)",
758 gnutls_strerror (err), (int) in, (int) out);
759 goto error;
761 debug ("TLS handshake completed");
762 debug_session (session);
764 /* Set up the connection recv/send/close functions so they call
765 * GnuTLS wrappers instead.
767 conn->crypto_session = session;
768 conn->recv = crypto_recv;
769 conn->send = crypto_send;
770 conn->close = crypto_close;
771 return 0;
773 error:
774 gnutls_deinit (session);
775 return -1;
778 #else /* !HAVE_GNUTLS */
780 /* GnuTLS was not available at compile time. These are stub versions
781 * of the above functions which either do nothing or report errors as
782 * appropriate.
785 void
786 crypto_init (bool tls_set_on_cli)
788 if (tls > 0) {
789 fprintf (stderr,
790 "%s: TLS cannot be enabled because "
791 "this binary was compiled without GnuTLS.\n",
792 program_name);
793 exit (EXIT_FAILURE);
796 tls = 0;
797 debug ("TLS disabled: nbdkit was not compiled with GnuTLS support");
800 void
801 crypto_free (void)
803 /* nothing */
807 crypto_negotiate_tls (int sockin, int sockout)
809 /* Should never be called because tls == 0. */
810 abort ();
813 #endif /* !HAVE_GNUTLS */