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
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
45 #include <sys/types.h>
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
65 #include <gnutls/socket.h>
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);
79 print_gnutls_error (int err
, const char *fs
, ...)
83 fprintf (stderr
, "%s: GnuTLS error: ", program_name
);
86 vfprintf (stderr
, fs
, 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
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
;
105 if (asprintf (&ca_cert_filename
, "%s/ca-cert.pem", path
) == -1) {
109 if (asprintf (&server_cert_filename
, "%s/server-cert.pem", path
) == -1) {
113 if (asprintf (&server_key_filename
, "%s/server-key.pem", path
) == -1) {
117 if (asprintf (&ca_crl_filename
, "%s/ca-crl.pem", path
) == -1) {
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)
127 if (access (server_cert_filename
, R_OK
) == -1)
129 if (access (server_key_filename
, R_OK
) == -1)
132 /* Any problem past here is a hard error. */
134 err
= gnutls_certificate_allocate_credentials (&x509_creds
);
136 print_gnutls_error (err
, "allocating credentials");
139 err
= gnutls_certificate_set_x509_trust_file (x509_creds
, ca_cert_filename
,
140 GNUTLS_X509_FMT_PEM
);
142 print_gnutls_error (err
, "loading %s", ca_cert_filename
);
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
);
150 print_gnutls_error (err
, "loading %s", ca_crl_filename
);
155 err
= gnutls_certificate_set_x509_key_file (x509_creds
,
156 server_cert_filename
,
158 GNUTLS_X509_FMT_PEM
);
160 print_gnutls_error (err
, "loading server certificate and key (%s, %s)",
161 server_cert_filename
, server_key_filename
);
165 debug ("successfully loaded TLS certificates from %s", path
);
170 start_certificates (void)
172 /* Try to locate the certificates directory and load them. */
173 if (tls_certificates_dir
== NULL
) {
175 CLEANUP_FREE
char *path
= NULL
;
178 #define RUNNING_AS_NON_ROOT_FOR_CERTIFICATES_DIR (geteuid () != 0)
180 #define RUNNING_AS_NON_ROOT_FOR_CERTIFICATES_DIR 0
182 if (RUNNING_AS_NON_ROOT_FOR_CERTIFICATES_DIR
) {
183 home
= getenv ("HOME");
185 if (asprintf (&path
, "%s/.pki/%s", home
, PACKAGE_NAME
) == -1) {
189 if (load_certificates (path
))
190 goto found_certificates
;
192 if (asprintf (&path
, "%s/.config/pki/%s", home
, PACKAGE_NAME
) == -1) {
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
;
206 if (load_certificates (tls_certificates_dir
))
207 goto found_certificates
;
212 #ifdef HAVE_GNUTLS_CERTIFICATE_SET_KNOWN_DH_PARAMS
213 gnutls_certificate_set_known_dh_params (x509_creds
, GNUTLS_SEC_PARAM_MEDIUM
);
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
) {
231 err
= gnutls_psk_allocate_server_credentials (&psk_creds
);
233 print_gnutls_error (err
, "allocating PSK credentials");
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
);
246 /* Initialize crypto. This also handles the command line parameters
247 * and loading the server certificate.
250 crypto_init (bool tls_set_on_cli
)
255 err
= gnutls_global_init ();
257 print_gnutls_error (err
, "initializing GnuTLS");
261 if (tls
== 0) /* --tls=off */
264 /* --tls-psk overrides certificates. */
265 if (tls_psk
!= NULL
) {
266 what
= "Pre-Shared Keys (PSK)";
269 crypto_auth
= CRYPTO_AUTH_PSK
;
272 what
= "X.509 certificates";
273 r
= start_certificates ();
275 crypto_auth
= CRYPTO_AUTH_CERTIFICATES
;
279 debug ("TLS enabled using: %s", what
);
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 */
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",
296 /* If --tls=on was given on the command line, warn before we turn
299 if (tls
== 1 && tls_set_on_cli
) { /* explicit --tls=on */
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",
309 debug ("TLS disabled: could not load TLS certificates");
316 switch (crypto_auth
) {
317 case CRYPTO_AUTH_CERTIFICATES
:
318 gnutls_certificate_free_credentials (x509_creds
);
320 case CRYPTO_AUTH_PSK
:
321 gnutls_psk_free_server_credentials (psk_creds
);
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).
333 crypto_recv (void *vbuf
, size_t len
)
336 gnutls_session_t session
= conn
->crypto_session
;
339 bool first_read
= true;
341 assert (session
!= NULL
);
344 r
= gnutls_record_recv (session
, buf
, len
);
346 if (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
)
348 nbdkit_error ("gnutls_record_recv: %s", gnutls_strerror (r
));
355 /* Partial record read. This is an error. */
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.
377 crypto_send (const void *vbuf
, size_t len
, int flags
)
380 gnutls_session_t session
= conn
->crypto_session
;
381 const char *buf
= vbuf
;
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)
390 else if (flags
& SEND_MORE
)
391 gnutls_record_cork (session
);
394 r
= gnutls_record_send (session
, buf
, len
);
396 if (r
== GNUTLS_E_INTERRUPTED
|| r
== GNUTLS_E_AGAIN
)
404 if (!(flags
& SEND_MORE
) &&
405 gnutls_record_uncork (session
, GNUTLS_RECORD_WAIT
) < 0)
411 /* There's no place in the NBD protocol to send back errors from
412 * close, so this function ignores errors.
415 crypto_close (int how
)
418 gnutls_session_t session
= conn
->crypto_session
;
421 assert (session
!= NULL
);
424 gnutls_bye (session
, GNUTLS_SHUT_WR
);
426 gnutls_transport_get_int2 (session
, &sockin
, &sockout
);
428 gnutls_bye (session
, GNUTLS_SHUT_RDWR
);
431 closesocket (sockin
);
432 if (sockout
>= 0 && sockin
!= sockout
)
433 closesocket (sockout
);
435 gnutls_deinit (session
);
436 conn
->crypto_session
= NULL
;
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
446 push (gnutls_transport_ptr_t ptr
, const void *buf
, size_t n
)
450 r
= send ((intptr_t) ptr
, buf
, n
, 0);
451 /* XXX call gnutls_transport_set_errno here */
456 pull (gnutls_transport_ptr_t ptr
, void *buf
, size_t n
)
460 r
= recv ((intptr_t) ptr
, buf
, n
, 0);
461 /* XXX call gnutls_transport_set_errno here */
466 pull_timeout (gnutls_transport_ptr_t ptr
, unsigned ms
)
469 /* XXX This is what you're supposed to do, but I couldn't get it to
472 return gnutls_system_recv_timeout (ptr
, ms
);
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;
484 tls_log (int level
, const char *msg
)
487 CLEANUP_FREE
char *copy
= NULL
;
489 /* Strip trailing \n added by GnuTLS. */
491 if (len
> 0 && msg
[len
-1] == '\n') {
492 copy
= strndup (msg
, len
-1);
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;
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
517 nbdkit_debug ("TLS: no peer certificates found");
521 nbdkit_debug ("TLS: peer provided %u certificate(s)", cert_list_size
);
522 for (i
= 0; i
< cert_list_size
; ++i
) {
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
);
531 ret
= gnutls_x509_crt_import (cert
, &cert_list
[i
], GNUTLS_X509_FMT_DER
);
533 gnutls_x509_crt_deinit (cert
);
537 ret
= gnutls_x509_crt_print (cert
, GNUTLS_CRT_PRINT_ONELINE
, &cinfo
);
539 nbdkit_debug ("TLS: %s", cinfo
.data
);
540 gnutls_free (cinfo
.data
);
543 gnutls_x509_crt_deinit (cert
);
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;
554 const char *desc
, *username
, *hint
;
556 gnutls_transport_ktls_enable_flags_t ktls_enabled
;
559 if (nbdkit_debug_tls_session
<= 0)
562 desc
= gnutls_session_get_desc (session
);
563 if (desc
) nbdkit_debug ("TLS session: %s", desc
);
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;
575 if ((int) ktls_enabled
== 0)
576 nbdkit_debug ("TLS: kTLS disabled");
578 nbdkit_debug ("TLS: kTLS enabled unknown setting: %d",
583 kx
= gnutls_kx_get (session
);
584 cred
= gnutls_auth_get_type (session
);
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
);
594 nbdkit_debug ("TLS: SRP session username: %s", username
);
597 nbdkit_debug ("TLS: authentication: PSK (Pre-Shared Key)");
598 hint
= gnutls_psk_client_get_hint (session
);
600 nbdkit_debug ("TLS: PSK hint: %s", hint
);
601 username
= gnutls_psk_server_get_username (session
);
603 nbdkit_debug ("TLS: PSK username: %s", username
);
604 if (kx
== GNUTLS_KX_ECDHE_PSK
)
606 else if (kx
== GNUTLS_KX_DHE_PSK
)
609 case GNUTLS_CRD_ANON
:
610 nbdkit_debug ("TLS: authentication: anonymous");
611 if (kx
== GNUTLS_KX_ANON_ECDH
)
613 else if (kx
== GNUTLS_KX_ANON_DH
)
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
)
622 else if (kx
== GNUTLS_KX_ECDHE_RSA
|| kx
== GNUTLS_KX_ECDHE_ECDSA
)
626 nbdkit_debug ("TLS: authentication: unknown (%d)", (int) cred
);
629 #ifdef HAVE_GNUTLS_GROUP_GET
630 grp
= gnutls_group_get (session
);
635 nbdkit_debug ("TLS: negotiated group: "
636 #ifdef HAVE_GNUTLS_GROUP_GET_NAME
637 "%s", gnutls_group_get_name (grp
));
644 nbdkit_debug ("TLS: ephemeral ECDH using curve %s",
645 gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session
)));
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
)
660 gnutls_session_t session
;
661 CLEANUP_FREE
char *priority
= NULL
;
664 /* Create the GnuTLS session. */
665 err
= gnutls_init (&session
, GNUTLS_SERVER
);
667 nbdkit_error ("gnutls_init: %s", gnutls_strerror (err
));
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
,
681 nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err
));
685 /* If verify peer is enabled, tell GnuTLS to request the client
686 * certificates. (Note the default is to not request or verify
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);
694 abort (); /* Checked when we set the flag in main() */
698 priority
= strdup (TLS_PRIORITY
);
699 if (priority
== NULL
) {
700 nbdkit_error ("strdup: %m");
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
);
709 nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err
));
713 if (asprintf (&priority
,
714 "%s:+ECDHE-PSK:+DHE-PSK:+PSK", TLS_PRIORITY
) == -1) {
715 nbdkit_error ("asprintf: %m");
724 assert (priority
!= NULL
);
725 err
= gnutls_priority_set_direct (session
, priority
, NULL
);
727 nbdkit_error ("failed to set TLS session priority to %s: %s",
728 priority
, gnutls_strerror (err
));
732 /* Set up GnuTLS so it reads and writes on the raw sockets. */
733 gnutls_transport_set_int2 (session
, sockin
, sockout
);
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
);
740 /* Perform the handshake. */
741 debug ("starting TLS handshake");
742 gnutls_handshake_set_timeout (session
,
743 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT
);
746 err
= gnutls_handshake (session
);
747 } while (err
< 0 && gnutls_error_is_fatal (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
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
);
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
;
774 gnutls_deinit (session
);
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
786 crypto_init (bool tls_set_on_cli
)
790 "%s: TLS cannot be enabled because "
791 "this binary was compiled without GnuTLS.\n",
797 debug ("TLS disabled: nbdkit was not compiled with GnuTLS support");
807 crypto_negotiate_tls (int sockin
, int sockout
)
809 /* Should never be called because tls == 0. */
813 #endif /* !HAVE_GNUTLS */