1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Rick Macklem 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. 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. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/queue.h> 31 #include <sys/syslog.h> 32 #include <sys/select.h> 33 #include <sys/time.h> 34 35 #include <netdb.h> 36 #include <signal.h> 37 #include <stdarg.h> 38 #include <stdbool.h> 39 #include <string.h> 40 41 #include <rpc/rpc.h> 42 43 #include <openssl/opensslconf.h> 44 #include <openssl/bio.h> 45 #include <openssl/ssl.h> 46 #include <openssl/err.h> 47 #include <openssl/x509v3.h> 48 49 #include "rpc.tlscommon.h" 50 51 /* 52 * How long to delay a reload of the CRL when there are RPC request(s) 53 * to process, in usec. Must be less than 1second. 54 */ 55 #define RELOADDELAY 250000 56 57 void 58 rpctls_svc_run(void) 59 { 60 int ret; 61 struct timeval tv; 62 fd_set readfds; 63 uint64_t curtime, nexttime; 64 struct timespec tp; 65 sigset_t sighup_mask; 66 67 /* Expand svc_run() here so that we can call rpctls_loadcrlfile(). */ 68 curtime = nexttime = 0; 69 sigemptyset(&sighup_mask); 70 sigaddset(&sighup_mask, SIGHUP); 71 for (;;) { 72 clock_gettime(CLOCK_MONOTONIC, &tp); 73 curtime = tp.tv_sec; 74 curtime = curtime * 1000000 + tp.tv_nsec / 1000; 75 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 76 if (rpctls_gothup && curtime >= nexttime) { 77 rpctls_gothup = false; 78 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 79 ret = rpctls_loadcrlfile(rpctls_ctx); 80 if (ret != 0) 81 rpctls_checkcrl(); 82 else 83 rpctls_verbose_out("rpc.tlsservd: Can't " 84 "reload CRLfile\n"); 85 clock_gettime(CLOCK_MONOTONIC, &tp); 86 nexttime = tp.tv_sec; 87 nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 + 88 RELOADDELAY; 89 } else 90 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 91 92 /* 93 * If a reload is pending, poll for received request(s), 94 * otherwise set a RELOADDELAY timeout, since a SIGHUP 95 * could be processed between the got_sighup test and 96 * the select() system call. 97 */ 98 tv.tv_sec = 0; 99 if (rpctls_gothup) 100 tv.tv_usec = 0; 101 else 102 tv.tv_usec = RELOADDELAY; 103 readfds = svc_fdset; 104 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, &tv)) { 105 case -1: 106 if (errno == EINTR) { 107 /* Allow a reload now. */ 108 nexttime = 0; 109 continue; 110 } 111 syslog(LOG_ERR, "rpc.tls daemon died: select: %m"); 112 exit(1); 113 case 0: 114 /* Allow a reload now. */ 115 nexttime = 0; 116 continue; 117 default: 118 svc_getreqset(&readfds); 119 } 120 } 121 } 122 123 /* 124 * (re)load the CRLfile into the certificate verification store. 125 */ 126 int 127 rpctls_loadcrlfile(SSL_CTX *ctx) 128 { 129 X509_STORE *certstore; 130 X509_LOOKUP *certlookup; 131 int ret; 132 133 if ((rpctls_verify_cafile != NULL || 134 rpctls_verify_capath != NULL) && 135 rpctls_crlfile != NULL) { 136 certstore = SSL_CTX_get_cert_store(ctx); 137 certlookup = X509_STORE_add_lookup( 138 certstore, X509_LOOKUP_file()); 139 ret = 0; 140 if (certlookup != NULL) 141 ret = X509_load_crl_file(certlookup, 142 rpctls_crlfile, X509_FILETYPE_PEM); 143 if (ret != 0) 144 ret = X509_STORE_set_flags(certstore, 145 X509_V_FLAG_CRL_CHECK | 146 X509_V_FLAG_CRL_CHECK_ALL); 147 if (ret == 0) { 148 rpctls_verbose_out( 149 "rpctls_loadcrlfile: Can't" 150 " load CRLfile=%s\n", 151 rpctls_crlfile); 152 return (ret); 153 } 154 } 155 return (1); 156 } 157 158 /* 159 * Read the CRL file and check for any extant connections 160 * that might now be revoked. 161 */ 162 void 163 rpctls_checkcrl(void) 164 { 165 struct ssl_entry *slp; 166 BIO *infile; 167 X509_CRL *crl; 168 X509_REVOKED *revoked; 169 char *cp, *cp2, nullstr[1]; 170 int ret; 171 172 if (rpctls_crlfile == NULL || (rpctls_verify_cafile == NULL && 173 rpctls_verify_capath == NULL)) 174 return; 175 infile = BIO_new(BIO_s_file()); 176 if (infile == NULL) { 177 rpctls_verbose_out("rpctls_checkcrl: Cannot BIO_new\n"); 178 return; 179 } 180 ret = BIO_read_filename(infile, rpctls_crlfile); 181 if (ret != 1) { 182 rpctls_verbose_out("rpctls_checkcrl: Cannot read CRL file\n"); 183 BIO_free(infile); 184 return; 185 } 186 187 nullstr[0] = '\0'; 188 for (crl = PEM_read_bio_X509_CRL(infile, NULL, NULL, nullstr); 189 crl != NULL; crl = PEM_read_bio_X509_CRL(infile, NULL, NULL, 190 nullstr)) { 191 LIST_FOREACH(slp, &rpctls_ssllist, next) { 192 if (slp->cert != NULL) { 193 ret = X509_CRL_get0_by_cert(crl, &revoked, 194 slp->cert); 195 /* 196 * Do a shutdown on the socket, so that it 197 * can no longer be used. The kernel RPC 198 * code will notice the socket is disabled 199 * and will do a disconnect upcall, which will 200 * close the socket. 201 */ 202 if (ret == 1) { 203 cp2 = X509_NAME_oneline( 204 X509_get_subject_name(slp->cert), 205 NULL, 0); 206 cp = X509_NAME_oneline( 207 X509_get_issuer_name(slp->cert), 208 NULL, 0); 209 if (rpctls_debug_level == 0) 210 syslog(LOG_INFO | LOG_DAEMON, 211 "rpctls_daemon: Certificate" 212 " Revoked " 213 "issuerName=%s " 214 "subjectName=%s: " 215 "TCP connection closed", 216 cp, cp2); 217 else 218 fprintf(stderr, 219 "rpctls_daemon: Certificate" 220 " Revoked " 221 "issuerName=%s " 222 "subjectName=%s: " 223 "TCP connection closed", 224 cp, cp2); 225 shutdown(slp->s, SHUT_WR); 226 slp->shutoff = true; 227 } 228 } 229 } 230 X509_CRL_free(crl); 231 } 232 BIO_free(infile); 233 } 234 235 void 236 rpctls_verbose_out(const char *fmt, ...) 237 { 238 va_list ap; 239 240 if (rpctls_verbose) { 241 va_start(ap, fmt); 242 if (rpctls_debug_level == 0) 243 vsyslog(LOG_INFO | LOG_DAEMON, fmt, ap); 244 else 245 vfprintf(stderr, fmt, ap); 246 va_end(ap); 247 } 248 } 249 250 /* 251 * Check a IP address against any host address in the 252 * certificate. Basically getnameinfo(3) and 253 * X509_check_host(). 254 */ 255 int 256 rpctls_checkhost(struct sockaddr *sad, X509 *cert, unsigned int wildcard) 257 { 258 char hostnam[NI_MAXHOST]; 259 int ret; 260 261 if (getnameinfo((const struct sockaddr *)sad, 262 sad->sa_len, hostnam, sizeof(hostnam), 263 NULL, 0, NI_NAMEREQD) != 0) 264 return (0); 265 rpctls_verbose_out("rpctls_checkhost: DNS %s\n", 266 hostnam); 267 ret = X509_check_host(cert, hostnam, strlen(hostnam), 268 wildcard, NULL); 269 return (ret); 270 } 271 272 /* 273 * Get the peer's IP address. 274 */ 275 int 276 rpctls_gethost(int s, struct sockaddr *sad, char *hostip, size_t hostlen) 277 { 278 socklen_t slen; 279 int ret; 280 281 slen = sizeof(struct sockaddr_storage); 282 if (getpeername(s, sad, &slen) < 0) 283 return (0); 284 ret = 0; 285 if (getnameinfo((const struct sockaddr *)sad, 286 sad->sa_len, hostip, hostlen, 287 NULL, 0, NI_NUMERICHOST) == 0) { 288 rpctls_verbose_out("rpctls_gethost: %s\n", 289 hostip); 290 ret = 1; 291 } 292 return (ret); 293 } 294