svn commit: r359225 - in projects/nfs-over-tls/usr.sbin: rpctlscd rpctlssd
Rick Macklem
rmacklem at FreeBSD.org
Sun Mar 22 19:31:13 UTC 2020
Author: rmacklem
Date: Sun Mar 22 19:31:12 2020
New Revision: 359225
URL: https://svnweb.freebsd.org/changeset/base/359225
Log:
Update the rpctlscd daemon in various ways, including the addition of
support for upcalls for TLS connections already established.
The current "SSL *"s are maintained in a linked list referenced by a
uint64_t refno.
Also, update rpctlssd.8, which got missed in the last commit.
Modified:
projects/nfs-over-tls/usr.sbin/rpctlscd/Makefile
projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.8
projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c
projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.8
Modified: projects/nfs-over-tls/usr.sbin/rpctlscd/Makefile
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpctlscd/Makefile Sun Mar 22 19:23:43 2020 (r359224)
+++ projects/nfs-over-tls/usr.sbin/rpctlscd/Makefile Sun Mar 22 19:31:12 2020 (r359225)
@@ -7,7 +7,6 @@ MAN= rpctlscd.8
SRCS= rpctlscd.c rpctlscd.h rpctlscd_svc.c rpctlscd_xdr.c
CFLAGS+= -I.
-WARNS?= 1
LIBADD= ssl crypto
Modified: projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.8
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.8 Sun Mar 22 19:23:43 2020 (r359224)
+++ projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.8 Sun Mar 22 19:31:12 2020 (r359225)
@@ -26,7 +26,7 @@
.\" $FreeBSD$
.\"
.\" Modified from gssd.8 for rpctlscd.8 by Rick Macklem.
-.Dd January 21, 2020
+.Dd March 11, 2020
.Dt RPCTLSCD 8
.Os
.Sh NAME
@@ -34,21 +34,91 @@
.Nd "Sun RPC over TLS Client Daemon"
.Sh SYNOPSIS
.Nm
+.Op Fl D Ar certdir
.Op Fl d
+.Op Fl h
+.Op Fl l Ar CAfile
+.Op Fl m
+.Op Fl p Ar CApath
+.Op Fl r Ar CRLfile
+.Op Fl V
.Op Fl v
.Sh DESCRIPTION
The
.Nm
program provides support for the client side of the kernel Sun RPC over TLS
implementation.
+This daemon must be running for the kernel RPC to be able to do a TLS
+connection to a server for an NFS over TLS mount.
.Pp
The options are as follows:
.Bl -tag -width indent
+.It Fl D Ar certdir
+Use ``certdir'' instead of /etc/rpctlscd for the
+.Fl c
+option.
.It Fl d
Run in debug mode.
In this mode,
.Nm
will not fork when it starts.
+.It Fl h
+This option specifies that the certificate provided by the server during
+TLS handshake must have the Fully Qualified Domain Name for the server's
+IP address in either the subjectAltName or commonName field of the
+certificate.
+This option is meaningless unless the
+.FL V
+option is also specified.
+.It Fl l Ar CAfile
+This specifies the path name of a CAfile which holds the information
+for server certificate verification.
+This path name is used in
+.Dq SSL_CTX_load_verify_locations(ctx,CAfile,NULL)
+and
+.Dq SSL_CTX_set0_CA_list(ctx,SSL_load_client_CA_file(CAfile))
+calls.
+Note that this is a path name for the file and is not assumed to be
+in ``certdir''.
+This option may need to be specified when the
+.Fl V
+option is specified.
+.It Fl m
+Enable support for mutual authentication.
+A certificate must be found in /etc/rpctlscd (or the directory specified by
+.Fl D )
+in case a server requests a peer certificate.
+The certificate needs to be in a file named ``cert.pem'' and a key in
+a file named ``key.pem'' in the directory for this option to work.
+.It Fl p Ar CApath
+This option is similar to the
+.Fl l
+option, but specifies the path of a directory with CA
+certificates in it.
+When this option is used,
+.Dq SSL_CTX_set0_CA_list(ctx,SSL_load_client_CA_file())
+is not called, so a list of CA names might not be passed
+to the server during the TLS handshake.
+The openssl documentation indicates this call is rarely needed.
+(However, I was not able to determine if/when this matters, so
+if in doubt, use the
+.Fl l
+option instead of this option.)
+.It Fl r Ar CRLfile
+This option specifies a Certificate Revocation List (CRL) file
+that is to be loaded into the verify certificate store and
+checked during verification.
+This option is meaningless unless either the
+.Fl l
+or
+.Fl p
+have been specified.
+.It Fl V
+This option specifies that the certificate provided by the server
+during the TLS handshake must verify.
+If this option is specified, the
+.Fl l
+option may also need to be specified.
.It Fl v
Run in verbose mode.
In this mode,
@@ -61,10 +131,17 @@ option has also been specified.
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
-.Xr openssl 3 ,
+.Xr openssl 1 ,
.Xr syslog 3 ,
.Xr mount_nfs 8 ,
.Xr rpctlssd 8
+.Sh BUGS
+This daemon cannot be safely shut down and restarted if there are
+any active RPC-over-TLS connections.
+Doing so will orphan the KERNEL_TLS connections, so that they
+can no longer do upcalls successfully, since the
+.Dq SSL *
+structures in userspace have been lost.
.Sh HISTORY
The
.Nm
Modified: projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c Sun Mar 22 19:23:43 2020 (r359224)
+++ projects/nfs-over-tls/usr.sbin/rpctlscd/rpctlscd.c Sun Mar 22 19:31:12 2020 (r359225)
@@ -34,9 +34,12 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
-#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/linker.h>
+#include <sys/module.h>
#include <sys/stat.h>
#include <sys/syslog.h>
+#include <sys/time.h>
#include <err.h>
#include <netdb.h>
#include <signal.h>
@@ -47,8 +50,6 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
-#include <arpa/inet.h>
-
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/rpcsec_tls.h>
@@ -66,20 +67,46 @@ __FBSDID("$FreeBSD$");
#ifndef _PATH_CERTANDKEY
#define _PATH_CERTANDKEY "/etc/rpctlscd/"
#endif
+#ifndef _PREFERRED_CIPHERS
+#define _PREFERRED_CIPHERS "SHA384:SHA256:!CAMELLIA"
+#endif
static int rpctls_debug_level;
static bool rpctls_verbose;
static int testnossl;
static SSL_CTX *rpctls_ctx = NULL;
static const char *rpctls_verify_cafile = NULL;
+static const char *rpctls_verify_capath = NULL;
+static const char *rpctls_crlfile = NULL;
static const char *rpctls_certdir = _PATH_CERTANDKEY;
static bool rpctls_verify = false;
static bool rpctls_comparehost = false;
+static uint64_t rpctls_ssl_refno = 0;
+static uint64_t rpctls_ssl_sec = 0;
+static uint64_t rpctls_ssl_usec = 0;
+static bool rpctls_gothup = false;
+/*
+ * A linked list of all current "SSL *"s and socket "fd"s
+ * for kernel RPC TLS connections is maintained.
+ * The "refno" field is a unique 64bit value used to
+ * identify which entry a kernel RPC upcall refers to.
+ */
+LIST_HEAD(ssl_list, ssl_entry);
+struct ssl_entry {
+ LIST_ENTRY(ssl_entry) next;
+ uint64_t refno;
+ int s;
+ SSL *ssl;
+};
+static struct ssl_list rpctls_ssllist;
+
static void rpctlscd_terminate(int);
static SSL_CTX *rpctls_setupcl_ssl(bool cert);
static SSL *rpctls_connect(SSL_CTX *ctx, int s);
static int rpctls_checkhost(int s, X509 *cert);
+static int rpctls_loadfiles(SSL_CTX *ctx);
+static void rpctls_huphandler(int sig __unused);
extern void rpctlscd_1(struct svc_req *rqstp, SVCXPRT *transp);
extern int gssd_syscall(const char *path);
@@ -96,15 +123,19 @@ main(int argc, char **argv)
int fd, oldmask, ch;
SVCXPRT *xprt;
bool cert;
+ struct timeval tm;
+ struct timezone tz;
+ /* Get the time when this daemon is started. */
+ gettimeofday(&tm, &tz);
+ rpctls_ssl_sec = tm.tv_sec;
+ rpctls_ssl_usec = tm.tv_usec;
+
rpctls_verbose = false;
testnossl = 0;
cert = false;
- while ((ch = getopt(argc, argv, "cD:dhl:tVv")) != -1) {
+ while ((ch = getopt(argc, argv, "D:dhl:mp:rtVv")) != -1) {
switch (ch) {
- case 'c':
- cert = true;
- break;
case 'D':
rpctls_certdir = optarg;
break;
@@ -117,6 +148,15 @@ main(int argc, char **argv)
case 'l':
rpctls_verify_cafile = optarg;
break;
+ case 'm':
+ cert = true;
+ break;
+ case 'p':
+ rpctls_verify_capath = optarg;
+ break;
+ case 'r':
+ rpctls_crlfile = optarg;
+ break;
case 't':
testnossl = 1;
break;
@@ -127,15 +167,22 @@ main(int argc, char **argv)
rpctls_verbose = true;
break;
default:
- fprintf(stderr, "usage: %s [-c] "
+ fprintf(stderr, "usage: %s "
"[-D certdir] [-d] [-h] "
- "[-l verify_locations_file] "
+ "[-l CAfile] [-m] "
+ "[-p CApath] [-r CRLfile] "
"[-V] [-v]\n", argv[0]);
exit(1);
break;
}
}
+ if (modfind("krpc") < 0) {
+ /* Not present in kernel, try loading it */
+ if (kldload("krpc") < 0 || modfind("krpc") < 0)
+ errx(1, "Kernel RPC is not available");
+ }
+
if (!rpctls_debug_level) {
if (daemon(0, 0) != 0)
err(1, "Can't daemonize");
@@ -145,6 +192,7 @@ main(int argc, char **argv)
}
signal(SIGTERM, rpctlscd_terminate);
signal(SIGPIPE, rpctlscd_terminate);
+ signal(SIGHUP, rpctls_huphandler);
memset(&sun, 0, sizeof sun);
sun.sun_family = AF_LOCAL;
@@ -203,6 +251,7 @@ main(int argc, char **argv)
}
err(1, "Can't set up TSL context");
}
+ LIST_INIT(&rpctls_ssllist);
gssd_syscall(_PATH_RPCTLSCDSOCK);
svc_run();
@@ -237,13 +286,15 @@ rpctlscd_null_1_svc(void *argp, void *result, struct s
}
bool_t
-rpctlscd_connect_1_svc(void *argp, void *result, struct svc_req *rqstp)
+rpctlscd_connect_1_svc(void *argp,
+ struct rpctlscd_connect_res *result, struct svc_req *rqstp)
{
int s;
bool_t res;
SSL *ssl;
char buf[1024];
ssize_t siz, ret;
+ struct ssl_entry *newslp;
rpctlscd_verbose_out("rpctlsd_connect: started\n");
/* Get the socket fd from the kernel. */
@@ -257,6 +308,14 @@ rpctlscd_verbose_out("rpctlsd_connect s=%d\n", s);
if (ssl == NULL)
rpctlscd_verbose_out("rpctlsd_connect: can't do TLS "
"handshake\n");
+ else {
+ result->sec = rpctls_ssl_sec;
+ result->usec = rpctls_ssl_usec;
+ result->ssl = ++rpctls_ssl_refno;
+ /* Hard to believe this will ever wrap around.. */
+ if (rpctls_ssl_refno == 0)
+ result->ssl = ++rpctls_ssl_refno;
+ }
if (testnossl != 0 && ssl != NULL) {
/* Read the 478 bytes of junk off the socket. */
siz = 478;
@@ -267,13 +326,58 @@ rpctlscd_verbose_out("rpctlsd_connect s=%d\n", s);
}
}
- /* Done with socket fd, so let the kernel know. */
- gssd_syscall("D");
- if (ssl == NULL)
+ if (ssl == NULL) {
+ /*
+ * For RPC-over-TLS, this upcall is expected
+ * to close off the socket.
+ */
+ shutdown(s, SHUT_WR);
+ close(s);
return (FALSE);
+ }
+
+ /* Maintain list of all current SSL *'s */
+ newslp = malloc(sizeof(*newslp));
+ newslp->refno = rpctls_ssl_refno;
+ newslp->s = s;
+ newslp->ssl = ssl;
+ LIST_INSERT_HEAD(&rpctls_ssllist, newslp, next);
return (TRUE);
}
+bool_t
+rpctlscd_disconnect_1_svc(struct rpctlscd_disconnect_arg *argp,
+ void *result, struct svc_req *rqstp)
+{
+ struct ssl_entry *slp;
+
+ slp = NULL;
+ if (argp->sec == rpctls_ssl_sec && argp->usec ==
+ rpctls_ssl_usec) {
+ LIST_FOREACH(slp, &rpctls_ssllist, next) {
+ if (slp->refno == argp->ssl)
+ break;
+ }
+ }
+
+ if (slp != NULL) {
+ rpctlscd_verbose_out("rpctlscd_disconnect: fd=%d closed\n",
+ slp->s);
+ LIST_REMOVE(slp, next);
+ SSL_shutdown(slp->ssl);
+ SSL_free(slp->ssl);
+ /*
+ * For RPC-over-TLS, this upcall is expected
+ * to close off the socket.
+ */
+ shutdown(slp->s, SHUT_WR);
+ close(slp->s);
+ free(slp);
+ } else
+ return (FALSE);
+ return (TRUE);
+}
+
int
rpctlscd_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
{
@@ -298,6 +402,8 @@ rpctls_setupcl_ssl(bool cert)
size_t len, rlen;
int ret;
+ SSL_library_init();
+ SSL_load_error_strings();
OpenSSL_add_all_algorithms();
ctx = SSL_CTX_new(TLS_client_method());
@@ -309,6 +415,18 @@ rpctls_setupcl_ssl(bool cert)
SSL_CTX_set_ecdh_auto(ctx, 1);
/*
+ * Set preferred ciphers, since KERN_TLS only supports a
+ * few of them.
+ */
+ ret = SSL_CTX_set_cipher_list(ctx, _PREFERRED_CIPHERS);
+ if (ret == 0) {
+ rpctlscd_verbose_out("rpctls_setupcl_ssl: "
+ "SSL_CTX_set_cipher_list failed to set any ciphers\n");
+ SSL_CTX_free(ctx);
+ return (NULL);
+ }
+
+ /*
* If cert is true, a certificate and key exists in
* rpctls_certdir, so that it can do mutual authentication.
*/
@@ -341,15 +459,32 @@ rpctls_setupcl_ssl(bool cert)
return (NULL);
}
}
- if (rpctls_verify_cafile != NULL) {
+ if (rpctls_verify_cafile != NULL || rpctls_verify_capath != NULL) {
+ if (rpctls_crlfile != NULL) {
+ ret = rpctls_loadfiles(ctx);
+ if (ret == 0) {
+ rpctlscd_verbose_out("rpctls_setup_ssl: "
+ "Load CAfile, CRLfile failed\n");
+ SSL_CTX_free(ctx);
+ return (NULL);
+ }
+ }
ret = SSL_CTX_load_verify_locations(ctx,
- rpctls_verify_cafile, NULL);
+ rpctls_verify_cafile, rpctls_verify_capath);
if (ret != 1) {
rpctlscd_verbose_out("rpctls_setupcl_ssl: "
"Can't load verify locations\n");
SSL_CTX_free(ctx);
return (NULL);
}
+ /*
+ * The man page says that the
+ * SSL_CTX_set0_CA_list() call is not normally
+ * needed, but I believe it is harmless.
+ */
+ if (rpctls_verify_cafile != NULL)
+ SSL_CTX_set0_CA_list(ctx,
+ SSL_load_client_CA_file(rpctls_verify_cafile));
}
/* RPC-over-TLS must use TLSv1.3. */
@@ -371,6 +506,13 @@ rpctls_connect(SSL_CTX *ctx, int s)
int ret;
char *cp;
+ if (rpctls_gothup) {
+ rpctls_gothup = false;
+ ret = rpctls_loadfiles(ctx);
+ if (ret == 0)
+ rpctlscd_verbose_out("rpctls_connect: Can't "
+ "load CAfile, CRLfile\n");
+ }
ssl = SSL_new(ctx);
if (ssl == NULL) {
rpctlscd_verbose_out("rpctls_connect: "
@@ -400,6 +542,8 @@ rpctls_connect(SSL_CTX *ctx, int s)
SSL_free(ssl);
return (NULL);
}
+ cp = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
+ rpctlscd_verbose_out("rpctls_connect: cert issuerName=%s\n", cp);
cp = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
rpctlscd_verbose_out("rpctls_connect: cert subjectName=%s\n", cp);
ret = SSL_get_verify_result(ssl);
@@ -433,11 +577,8 @@ static int
rpctls_checkhost(int s, X509 *cert)
{
struct sockaddr *sad;
- struct sockaddr_in *sin;
- struct sockaddr_in6 *sin6;
struct sockaddr_storage ad;
- char hostnam[NI_MAXHOST + 1], addrstr[INET6_ADDRSTRLEN + 1];
- const char *cp;
+ char hostnam[NI_MAXHOST];
socklen_t slen;
int ret;
@@ -445,39 +586,72 @@ rpctls_checkhost(int s, X509 *cert)
slen = sizeof(ad);
if (getpeername(s, sad, &slen) < 0)
return (0);
- switch (sad->sa_family) {
- case AF_INET:
- sin = (struct sockaddr_in *)sad;
- cp = inet_ntop(sad->sa_family, &sin->sin_addr.s_addr,
- addrstr, sizeof(addrstr));
- if (cp != NULL)
- rpctlscd_verbose_out("rpctls_checkhost: "
- "peer ip %s\n", cp);
- if (getnameinfo((const struct sockaddr *)sad,
- sizeof(struct sockaddr_in), hostnam,
- sizeof(hostnam), NULL, 0, NI_NAMEREQD) != 0)
- return (0);
- break;
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)sad;
- cp = inet_ntop(sad->sa_family, &sin6->sin6_addr,
- addrstr, sizeof(addrstr));
- if (cp != NULL)
- rpctlscd_verbose_out("rpctls_checkhost: "
- "peer ip %s\n", cp);
- if (getnameinfo((const struct sockaddr *)sad,
- sizeof(struct sockaddr_in6), hostnam,
- sizeof(hostnam), NULL, 0, NI_NAMEREQD) != 0)
- return (0);
- break;
- default:
+ if (getnameinfo((const struct sockaddr *)sad,
+ sad->sa_len, hostnam, sizeof(hostnam),
+ NULL, 0, NI_NUMERICHOST) == 0)
+ rpctlscd_verbose_out("rpctls_checkhost: %s\n",
+ hostnam);
+ if (getnameinfo((const struct sockaddr *)sad,
+ sad->sa_len, hostnam, sizeof(hostnam),
+ NULL, 0, NI_NAMEREQD) != 0)
return (0);
- }
- rpctlscd_verbose_out("rpctls_checkhost: hostname %s\n",
- hostnam);
+ rpctlscd_verbose_out("rpctls_checkhost: DNS %s\n", hostnam);
ret = X509_check_host(cert, hostnam, strlen(hostnam), 0, NULL);
- rpctlscd_verbose_out("rpctls_checkhost: X509_check_host ret=%d\n",
- ret);
return (ret);
+}
+
+/*
+ * Load the CAfile (and optionally CRLfile) into the certificate
+ * verification store.
+ */
+static int
+rpctls_loadfiles(SSL_CTX *ctx)
+{
+ X509_STORE *certstore;
+ X509_LOOKUP *certlookup;
+ int ret;
+
+ if (rpctls_verify_cafile != NULL ||
+ rpctls_verify_capath != NULL) {
+ if (rpctls_crlfile != NULL) {
+ certstore = SSL_CTX_get_cert_store(ctx);
+ certlookup = X509_STORE_add_lookup(
+ certstore, X509_LOOKUP_file());
+ ret = 0;
+ if (certlookup != NULL)
+ ret = X509_load_crl_file(certlookup,
+ rpctls_crlfile, X509_FILETYPE_PEM);
+ if (ret != 0)
+ ret = X509_STORE_set_flags(certstore,
+ X509_V_FLAG_CRL_CHECK |
+ X509_V_FLAG_CRL_CHECK_ALL);
+ if (ret == 0) {
+ rpctlscd_verbose_out(
+ "rpctls_loadfiles: Can't"
+ " load CRLfile=%s\n",
+ rpctls_crlfile);
+ return (ret);
+ }
+ }
+ ret = SSL_CTX_load_verify_locations(ctx,
+ rpctls_verify_cafile, rpctls_verify_capath);
+ if (ret == 0) {
+ rpctlscd_verbose_out("rpctls_loadfiles: "
+ "Can't load verify locations\n");
+ return (ret);
+ }
+ if (rpctls_verify_cafile != NULL)
+ SSL_CTX_set_client_CA_list(ctx,
+ SSL_load_client_CA_file(
+ rpctls_verify_cafile));
+ }
+ return (1);
+}
+
+static void
+rpctls_huphandler(int sig __unused)
+{
+
+ rpctls_gothup = true;
}
Modified: projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.8
==============================================================================
--- projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.8 Sun Mar 22 19:23:43 2020 (r359224)
+++ projects/nfs-over-tls/usr.sbin/rpctlssd/rpctlssd.8 Sun Mar 22 19:31:12 2020 (r359225)
@@ -26,7 +26,7 @@
.\" $FreeBSD$
.\"
.\" Modified from gssd.8 for rpctlssd.8 by Rick Macklem.
-.Dd January 21, 2020
+.Dd March 11, 2020
.Dt RPCTLSSD 8
.Os
.Sh NAME
@@ -34,21 +34,130 @@
.Nd "Sun RPC over TLS Server Daemon"
.Sh SYNOPSIS
.Nm
+.Op Fl D Ar certdir
.Op Fl d
+.Op Fl h
+.Op Fl l Ar CAfile
+.Op Fl m
+.Op Fl p Ar CApath
+.Op Fl r Ar CRLfile
.Op Fl v
.Sh DESCRIPTION
The
.Nm
program provides support for the server side of the kernel Sun RPC over TLS
implementation.
+This daemon must be running to allow the kernel RPC to perform the TLS
+handshake after a TCP client has sent the STARTTLS Null RPC request to
+the server.
+This is needed to support clients doing NFS over TLS.
+Note that the
+.Fl tls
+option in the
+.Xr exports 5
+file specifies that the client must use RPC over TLS and the
+.Fl tlscert
+option in the
+.Xr exports 5
+file specifies that the client must provide a certificate
+that verifies.
+For this latter case, the
+.Fl m
+and
+.Fl l
+options must be specified.
.Pp
+Also, if the IP address used by the client cannot be trusted,
+the rules in
+.Xr exports 5
+cannot be applied safely.
+As such, the
+.Fl h
+option can be used along with
+.Fl m
+and
+.Fl l
+options to require that the client certificate have the correct
+Fully Qualified Domain Name in it.
+.Pp
+A certificate and associated key must exist in /etc/rpctlssd
+(or the ``certdir'' specified by the
+.Fl D
+option)
+in files named ``cert.pem'' and ``key.pem''.
+.Pp
The options are as follows:
.Bl -tag -width indent
+.It Fl D Ar certdir
+Use ``certdir'' instead of /etc/rpctlssd as the location for the
+certificate in a file called ``cert.pem'' and key in ``key.pem''.
.It Fl d
Run in debug mode.
In this mode,
.Nm
will not fork when it starts.
+.It Fl h
+This option specifies that the client must provide a certificate
+that both verifies and has the Fully Qualified Domain Name (FQDN) for
+the IP address that the client uses to connect to the server
+in either the subjectAltName or commonName field of the
+certificate.
+With this option, a failure to verify the client certificate
+or find the FQDN in the certificate will result in the
+server sending AUTH_REJECTEDCRED replies to all client RPCs.
+This option requires the
+.Fl m
+and
+.Fl l
+options.
+.It Fl l Ar CAfile
+This option specifies the path name of a CA certificate(s) file
+in pem format, which is used to verify client certificates and to
+set the list of CA(s) sent to the client so that it knows which
+certificate to send to the server during the TLS handshake.
+This path name is used in
+.Dq SSL_CTX_load_verify_locations(ctx,CAfile,NULL)
+and
+.Dq SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile))
+openssl calls.
+Note that this is a path name for the file and is not assumed to be
+in ``certdir''.
+This option should be specified when the
+.Fl m
+option is specified so that the daemon can verify the client's
+certificate.
+.It Fl m
+This option specifies that the server is to request a certificate
+from the client during the TLS handshake.
+It does not require that the client provide a certificate.
+It should be specified unless no client doing RPC over TLS is
+required to have a certificate.
+For NFS, the export option
+.Fl tlscert
+will be used to require a client to provide a certificate
+that verifies.
+.It Fl p Ar CApath
+This option is similar to the
+.Fl l
+option, but specifies the path of a directory with CA
+certificates in it.
+When this option is used,
+.Dq SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file())
+is not called, so a list of CA names might not be passed
+to the client during the TLS handshake.
+(I was not able to determine if/when this matters, but
+if in doubt, use the
+.Fl l
+option instead of this option.)
+.It Fl r Ar CRLfile
+This option specifies a Certificate Revocation List (CRL) file
+that is to be loaded into the verify certificate store and
+checked during verification.
+This option is meaningless unless either the
+.Fl l
+or
+.Fl p
+have been specified.
.It Fl v
Run in verbose mode.
In this mode,
@@ -61,16 +170,20 @@ option has also been specified.
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
-.Xr openssl 3 ,
+.Xr openssl 1 ,
.Xr syslog 3 ,
+.Xr exports 5 ,
.Xr mount_nfs 8 ,
.Xr rpctlscd 8
+.Sh BUGS
+This daemon cannot be safely shut down and restarted if there are
+any active RPC-over-TLS connections.
+Doing so will orphan the KERNEL_TLS connections, so that they
+can no longer do upcalls successfully, since the
+.Dq SSL *
+structures in userspace have been lost.
.Sh HISTORY
The
.Nm
manual page first appeared in
.Fx 13.0 .
-.Sh AUTHORS
-This
-manual page was adapted from a manual page for the gssd daemon written by
-.An Doug Rabson Aq Mt dfr at FreeBSD.org .
More information about the svn-src-projects
mailing list