xref: /netbsd-src/usr.bin/ftp/ssl.c (revision 7d62b00eb9ad855ffcd7da46b41e23feb5476fac)
1 /*	$NetBSD: ssl.c,v 1.13 2023/02/25 12:07:25 mlelstv Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
5  * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
6  * Copyright (c) 2015 Thomas Klausner <wiz@NetBSD.org>
7  * Copyright (c) 2023 Michael van Elst <mlelstv@NetBSD.org>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer
15  *    in this position and unchanged.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __RCSID("$NetBSD: ssl.c,v 1.13 2023/02/25 12:07:25 mlelstv Exp $");
39 #endif
40 
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48 #include <unistd.h>
49 
50 #include <sys/param.h>
51 #include <sys/select.h>
52 #include <sys/uio.h>
53 
54 #include <netinet/tcp.h>
55 #include <netinet/in.h>
56 
57 #ifdef WITH_SSL
58 #include <openssl/crypto.h>
59 #include <openssl/x509.h>
60 #include <openssl/pem.h>
61 #include <openssl/ssl.h>
62 #include <openssl/err.h>
63 #endif
64 
65 #include "ssl.h"
66 
67 #include <stringlist.h>
68 #include <histedit.h>
69 #include <sys/poll.h>
70 #include "extern.h"
71 
72 extern int quit_time, verbose, ftp_debug;
73 extern FILE *ttyout;
74 
75 struct fetch_connect {
76 	int			 sd;		/* file/socket descriptor */
77 	char			*buf;		/* buffer */
78 	size_t			 bufsize;	/* buffer size */
79 	size_t			 bufpos;	/* position of buffer */
80 	size_t			 buflen;	/* length of buffer contents */
81 	struct {				/* data cached after an
82 						   interrupted read */
83 		char	*buf;
84 		size_t	 size;
85 		size_t	 pos;
86 		size_t	 len;
87 	} cache;
88 	int 			 issock;
89 	int			 iserr;
90 	int			 iseof;
91 #ifdef WITH_SSL
92 	SSL			*ssl;		/* SSL handle */
93 #endif
94 };
95 
96 /*
97  * Write a vector to a connection w/ timeout
98  * Note: can modify the iovec.
99  */
100 static ssize_t
101 fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
102 {
103 	struct timeval now, timeout, delta;
104 	fd_set writefds;
105 	ssize_t len, total;
106 	int fd = conn->sd;
107 	int r;
108 
109 	if (quit_time > 0) {
110 		FD_ZERO(&writefds);
111 		gettimeofday(&timeout, NULL);
112 		timeout.tv_sec += quit_time;
113 	}
114 
115 	total = 0;
116 	while (iovcnt > 0) {
117 		while (quit_time > 0 && !FD_ISSET(fd, &writefds)) {
118 			FD_SET(fd, &writefds);
119 			gettimeofday(&now, NULL);
120 			delta.tv_sec = timeout.tv_sec - now.tv_sec;
121 			delta.tv_usec = timeout.tv_usec - now.tv_usec;
122 			if (delta.tv_usec < 0) {
123 				delta.tv_usec += 1000000;
124 				delta.tv_sec--;
125 			}
126 			if (delta.tv_sec < 0) {
127 				errno = ETIMEDOUT;
128 				return -1;
129 			}
130 			errno = 0;
131 			r = select(fd + 1, NULL, &writefds, NULL, &delta);
132 			if (r == -1) {
133 				if (errno == EINTR)
134 					continue;
135 				return -1;
136 			}
137 		}
138 		errno = 0;
139 #ifdef WITH_SSL
140 		if (conn->ssl != NULL)
141 			len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
142 		else
143 #endif
144 			len = writev(fd, iov, iovcnt);
145 		if (len == 0) {
146 			/* we consider a short write a failure */
147 			/* XXX perhaps we shouldn't in the SSL case */
148 			errno = EPIPE;
149 			return -1;
150 		}
151 		if (len < 0) {
152 			if (errno == EINTR || errno == EAGAIN)
153 				continue;
154 			return -1;
155 		}
156 		total += len;
157 		while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) {
158 			len -= iov->iov_len;
159 			iov++;
160 			iovcnt--;
161 		}
162 		if (iovcnt > 0) {
163 			iov->iov_len -= len;
164 			iov->iov_base = (char *)iov->iov_base + len;
165 		}
166 	}
167 	return total;
168 }
169 
170 static ssize_t
171 fetch_write(const void *str, size_t len, struct fetch_connect *conn)
172 {
173 	struct iovec iov[1];
174 
175 	iov[0].iov_base = (char *)__UNCONST(str);
176 	iov[0].iov_len = len;
177 	return fetch_writev(conn, iov, 1);
178 }
179 
180 /*
181  * Send a formatted line; optionally echo to terminal
182  */
183 int
184 fetch_printf(struct fetch_connect *conn, const char *fmt, ...)
185 {
186 	va_list ap;
187 	size_t len;
188 	char *msg;
189 	int r;
190 
191 	va_start(ap, fmt);
192 	len = vasprintf(&msg, fmt, ap);
193 	va_end(ap);
194 
195 	if (msg == NULL) {
196 		errno = ENOMEM;
197 		return -1;
198 	}
199 
200 	r = fetch_write(msg, len, conn);
201 	free(msg);
202 	return r;
203 }
204 
205 int
206 fetch_fileno(struct fetch_connect *conn)
207 {
208 
209 	return conn->sd;
210 }
211 
212 int
213 fetch_error(struct fetch_connect *conn)
214 {
215 
216 	return conn->iserr;
217 }
218 
219 static void
220 fetch_clearerr(struct fetch_connect *conn)
221 {
222 
223 	conn->iserr = 0;
224 }
225 
226 int
227 fetch_flush(struct fetch_connect *conn)
228 {
229 
230 	if (conn->issock) {
231 		int fd = conn->sd;
232 		int v;
233 #ifdef TCP_NOPUSH
234 		v = 0;
235 		setsockopt(fd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v));
236 #endif
237 		v = 1;
238 		setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
239 	}
240 	return 0;
241 }
242 
243 /*ARGSUSED*/
244 struct fetch_connect *
245 fetch_open(const char *fname, const char *fmode)
246 {
247 	struct fetch_connect *conn;
248 	int fd;
249 
250 	fd = open(fname, O_RDONLY); /* XXX: fmode */
251 	if (fd < 0)
252 		return NULL;
253 
254 	if ((conn = calloc(1, sizeof(*conn))) == NULL) {
255 		close(fd);
256 		return NULL;
257 	}
258 
259 	conn->sd = fd;
260 	conn->issock = 0;
261 	return conn;
262 }
263 
264 /*ARGSUSED*/
265 struct fetch_connect *
266 fetch_fdopen(int sd, const char *fmode)
267 {
268 	struct fetch_connect *conn;
269 #if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH)
270 	int opt = 1;
271 #endif
272 
273 	if ((conn = calloc(1, sizeof(*conn))) == NULL)
274 		return NULL;
275 
276 	conn->sd = sd;
277 	conn->issock = 1;
278 	fcntl(sd, F_SETFD, FD_CLOEXEC);
279 #ifdef SO_NOSIGPIPE
280 	setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
281 #endif
282 #ifdef TCP_NOPUSH
283 	setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt));
284 #endif
285 	return conn;
286 }
287 
288 int
289 fetch_close(struct fetch_connect *conn)
290 {
291 	if (conn == NULL)
292 		return 0;
293 
294 	fetch_flush(conn);
295 #ifdef WITH_SSL
296 	SSL_free(conn->ssl);
297 #endif
298 	close(conn->sd);
299 	free(conn->cache.buf);
300 	free(conn->buf);
301 	free(conn);
302 	return 0;
303 }
304 
305 #define FETCH_WRITE_WAIT	-3
306 #define FETCH_READ_WAIT		-2
307 #define FETCH_READ_ERROR	-1
308 
309 #ifdef WITH_SSL
310 static ssize_t
311 fetch_ssl_read(SSL *ssl, void *buf, size_t len)
312 {
313 	ssize_t rlen;
314 	rlen = SSL_read(ssl, buf, len);
315 	if (rlen >= 0)
316 		return rlen;
317 
318 	switch (SSL_get_error(ssl, rlen)) {
319 	case SSL_ERROR_WANT_READ:
320 		return FETCH_READ_WAIT;
321 	case SSL_ERROR_WANT_WRITE:
322 		return FETCH_WRITE_WAIT;
323 	default:
324 		ERR_print_errors_fp(ttyout);
325 		return FETCH_READ_ERROR;
326 	}
327 }
328 #endif /* WITH_SSL */
329 
330 static ssize_t
331 fetch_nonssl_read(int sd, void *buf, size_t len)
332 {
333 	ssize_t rlen;
334 
335 	rlen = read(sd, buf, len);
336 	if (rlen == -1) {
337 		if (errno == EAGAIN || errno == EINTR)
338 			return FETCH_READ_WAIT;
339 		return FETCH_READ_ERROR;
340 	}
341 	return rlen;
342 }
343 
344 /*
345  * Cache some data that was read from a socket but cannot be immediately
346  * returned because of an interrupted system call.
347  */
348 static int
349 fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes)
350 {
351 
352 	if (conn->cache.size < nbytes) {
353 		char *tmp = realloc(conn->cache.buf, nbytes);
354 		if (tmp == NULL)
355 			return -1;
356 
357 		conn->cache.buf = tmp;
358 		conn->cache.size = nbytes;
359 	}
360 
361 	memcpy(conn->cache.buf, src, nbytes);
362 	conn->cache.len = nbytes;
363 	conn->cache.pos = 0;
364 	return 0;
365 }
366 
367 static int
368 fetch_wait(struct fetch_connect *conn, ssize_t rlen, struct timeval *timeout)
369 {
370 	struct timeval now, delta;
371 	int fd = conn->sd;
372 	fd_set fds;
373 
374 	FD_ZERO(&fds);
375 	while (!FD_ISSET(fd, &fds)) {
376 		FD_SET(fd, &fds);
377 		if (quit_time > 0) {
378 			gettimeofday(&now, NULL);
379 			if (!timercmp(timeout, &now, >)) {
380 				fprintf(ttyout, "\r\n%s: transfer aborted"
381 				    " because stalled for %lu sec.\r\n",
382 				    getprogname(), (unsigned long)quit_time);
383 				errno = ETIMEDOUT;
384 				conn->iserr = ETIMEDOUT;
385 				return -1;
386 			}
387 			timersub(timeout, &now, &delta);
388 		}
389 		errno = 0;
390 		if (select(fd + 1,
391 			rlen == FETCH_READ_WAIT ? &fds : NULL,
392 			rlen == FETCH_WRITE_WAIT ? &fds : NULL,
393 			NULL, quit_time > 0 ? &delta : NULL) < 0) {
394 			if (errno == EINTR)
395 				continue;
396 			conn->iserr = errno;
397 			return -1;
398 		}
399 	}
400 	return 0;
401 }
402 
403 size_t
404 fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
405 {
406 	ssize_t rlen, total;
407 	size_t len;
408 	char *start, *buf;
409 	struct timeval timeout;
410 
411 	if (quit_time > 0) {
412 		gettimeofday(&timeout, NULL);
413 		timeout.tv_sec += quit_time;
414 	}
415 
416 	total = 0;
417 	start = buf = ptr;
418 	len = size * nmemb;
419 
420 	if (conn->cache.len > 0) {
421 		/*
422 		 * The last invocation of fetch_read was interrupted by a
423 		 * signal after some data had been read from the socket. Copy
424 		 * the cached data into the supplied buffer before trying to
425 		 * read from the socket again.
426 		 */
427 		total = (conn->cache.len < len) ? conn->cache.len : len;
428 		memcpy(buf, conn->cache.buf, total);
429 
430 		conn->cache.len -= total;
431 		conn->cache.pos += total;
432 		len -= total;
433 		buf += total;
434 	}
435 
436 	while (len > 0) {
437 		/*
438 		 * The socket is non-blocking.  Instead of the canonical
439 		 * select() -> read(), we do the following:
440 		 *
441 		 * 1) call read() or SSL_read().
442 		 * 2) if an error occurred, return -1.
443 		 * 3) if we received data but we still expect more,
444 		 *    update our counters and loop.
445 		 * 4) if read() or SSL_read() signaled EOF, return.
446 		 * 5) if we did not receive any data but we're not at EOF,
447 		 *    call select().
448 		 *
449 		 * In the SSL case, this is necessary because if we
450 		 * receive a close notification, we have to call
451 		 * SSL_read() one additional time after we've read
452 		 * everything we received.
453 		 *
454 		 * In the non-SSL case, it may improve performance (very
455 		 * slightly) when reading small amounts of data.
456 		 */
457 #ifdef WITH_SSL
458 		if (conn->ssl != NULL)
459 			rlen = fetch_ssl_read(conn->ssl, buf, len);
460 		else
461 #endif
462 			rlen = fetch_nonssl_read(conn->sd, buf, len);
463 		switch (rlen) {
464 		case 0:
465 			conn->iseof = 1;
466 			return total;
467 		case FETCH_READ_ERROR:
468 			conn->iserr = errno;
469 			if (errno == EINTR)
470 				fetch_cache_data(conn, start, total);
471 			return 0;
472 		case FETCH_READ_WAIT:
473 		case FETCH_WRITE_WAIT:
474 			if (fetch_wait(conn, rlen, &timeout) == -1)
475 				return 0;
476 			break;
477 		default:
478 			len -= rlen;
479 			buf += rlen;
480 			total += rlen;
481 			break;
482 		}
483 	}
484 	return total;
485 }
486 
487 #define MIN_BUF_SIZE 1024
488 
489 /*
490  * Read a line of text from a connection w/ timeout
491  */
492 char *
493 fetch_getln(char *str, int size, struct fetch_connect *conn)
494 {
495 	size_t tmpsize;
496 	size_t len;
497 	char c;
498 
499 	if (conn->buf == NULL) {
500 		if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
501 			errno = ENOMEM;
502 			conn->iserr = 1;
503 			return NULL;
504 		}
505 		conn->bufsize = MIN_BUF_SIZE;
506 	}
507 
508 	if (conn->iserr || conn->iseof)
509 		return NULL;
510 
511 	if (conn->buflen - conn->bufpos > 0)
512 		goto done;
513 
514 	conn->buf[0] = '\0';
515 	conn->bufpos = 0;
516 	conn->buflen = 0;
517 	do {
518 		len = fetch_read(&c, sizeof(c), 1, conn);
519 		if (len == 0) {
520 			if (conn->iserr)
521 				return NULL;
522 			if (conn->iseof)
523 				break;
524 			abort();
525 		}
526 		conn->buf[conn->buflen++] = c;
527 		if (conn->buflen == conn->bufsize) {
528 			char *tmp = conn->buf;
529 			tmpsize = conn->bufsize * 2 + 1;
530 			if ((tmp = realloc(tmp, tmpsize)) == NULL) {
531 				errno = ENOMEM;
532 				conn->iserr = 1;
533 				return NULL;
534 			}
535 			conn->buf = tmp;
536 			conn->bufsize = tmpsize;
537 		}
538 	} while (c != '\n');
539 
540 	if (conn->buflen == 0)
541 		return NULL;
542  done:
543 	tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos));
544 	memcpy(str, conn->buf + conn->bufpos, tmpsize);
545 	str[tmpsize] = '\0';
546 	conn->bufpos += tmpsize;
547 	return str;
548 }
549 
550 int
551 fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
552     const char **errormsg)
553 {
554 	size_t len;
555 	int rv;
556 
557 	if (fetch_getln(buf, buflen, conn) == NULL) {
558 		if (conn->iseof) {	/* EOF */
559 			rv = -2;
560 			if (errormsg)
561 				*errormsg = "\nEOF received";
562 		} else {		/* error */
563 			rv = -1;
564 			if (errormsg)
565 				*errormsg = "Error encountered";
566 		}
567 		fetch_clearerr(conn);
568 		return rv;
569 	}
570 	len = strlen(buf);
571 	if (buf[len - 1] == '\n') {	/* clear any trailing newline */
572 		buf[--len] = '\0';
573 	} else if (len == buflen - 1) {	/* line too long */
574 		while (1) {
575 			char c;
576 			size_t rlen = fetch_read(&c, sizeof(c), 1, conn);
577 			if (rlen == 0 || c == '\n')
578 				break;
579 		}
580 		if (errormsg)
581 			*errormsg = "Input line is too long";
582 		fetch_clearerr(conn);
583 		return -3;
584 	}
585 	if (errormsg)
586 		*errormsg = NULL;
587 	return len;
588 }
589 
590 #ifdef WITH_SSL
591 void *
592 fetch_start_ssl(int sock, const char *servername)
593 {
594 	SSL *ssl;
595 	SSL_CTX *ctx;
596 	X509_VERIFY_PARAM *param;
597 	int ret, ssl_err;
598 	int verify = !ftp_truthy("sslnoverify", getoptionvalue("sslnoverify"), 0);
599 
600 	/* Init the SSL library and context */
601 	if (!SSL_library_init()){
602 		fprintf(ttyout, "SSL library init failed\n");
603 		return NULL;
604 	}
605 
606 	SSL_load_error_strings();
607 
608 	ctx = SSL_CTX_new(SSLv23_client_method());
609 	SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
610 	if (verify) {
611 		SSL_CTX_set_default_verify_paths(ctx);
612 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
613 	}
614 
615 	ssl = SSL_new(ctx);
616 	if (ssl == NULL){
617 		fprintf(ttyout, "SSL context creation failed\n");
618 		SSL_CTX_free(ctx);
619 		return NULL;
620 	}
621 
622 	if (verify) {
623 		param = SSL_get0_param(ssl);
624 		if (!X509_VERIFY_PARAM_set1_host(param, servername,
625 		    strlen(servername))) {
626 			fprintf(ttyout, "SSL verification setup failed\n");
627 			SSL_free(ssl);
628 			SSL_CTX_free(ctx);
629 			return NULL;
630 		}
631 
632 		/* Enable peer verification, (using the default callback) */
633 		SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
634 	}
635 
636 	SSL_set_fd(ssl, sock);
637 	if (!SSL_set_tlsext_host_name(ssl, __UNCONST(servername))) {
638 		fprintf(ttyout, "SSL hostname setting failed\n");
639 		SSL_free(ssl);
640 		SSL_CTX_free(ctx);
641 		return NULL;
642 	}
643 	while ((ret = SSL_connect(ssl)) == -1) {
644 		ssl_err = SSL_get_error(ssl, ret);
645 		if (ssl_err != SSL_ERROR_WANT_READ &&
646 		    ssl_err != SSL_ERROR_WANT_WRITE) {
647 			ERR_print_errors_fp(ttyout);
648 			SSL_free(ssl);
649 			SSL_CTX_free(ctx);
650 			return NULL;
651 		}
652 	}
653 
654 	if (ftp_debug && verbose) {
655 		X509 *cert;
656 		X509_NAME *name;
657 		char *str;
658 
659 		fprintf(ttyout, "SSL connection established using %s\n",
660 		    SSL_get_cipher(ssl));
661 		cert = SSL_get_peer_certificate(ssl);
662 		name = X509_get_subject_name(cert);
663 		str = X509_NAME_oneline(name, 0, 0);
664 		fprintf(ttyout, "Certificate subject: %s\n", str);
665 		free(str);
666 		name = X509_get_issuer_name(cert);
667 		str = X509_NAME_oneline(name, 0, 0);
668 		fprintf(ttyout, "Certificate issuer: %s\n", str);
669 		free(str);
670 	}
671 
672 	return ssl;
673 }
674 #endif /* WITH_SSL */
675 
676 
677 void
678 fetch_set_ssl(struct fetch_connect *conn, void *ssl)
679 {
680 #ifdef WITH_SSL
681 	conn->ssl = ssl;
682 #endif
683 }
684