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