Home | History | Annotate | Line # | Download | only in ftp
ssl.c revision 1.7
      1 /*	$NetBSD: ssl.c,v 1.7 2019/04/04 00:36:09 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.7 2019/04/04 00:36:09 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 r;
     92 
     93 	if (quit_time > 0) {
     94 		FD_ZERO(&writefds);
     95 		gettimeofday(&timeout, NULL);
     96 		timeout.tv_sec += quit_time;
     97 	}
     98 
     99 	total = 0;
    100 	while (iovcnt > 0) {
    101 		while (quit_time > 0 && !FD_ISSET(conn->sd, &writefds)) {
    102 			FD_SET(conn->sd, &writefds);
    103 			gettimeofday(&now, NULL);
    104 			delta.tv_sec = timeout.tv_sec - now.tv_sec;
    105 			delta.tv_usec = timeout.tv_usec - now.tv_usec;
    106 			if (delta.tv_usec < 0) {
    107 				delta.tv_usec += 1000000;
    108 				delta.tv_sec--;
    109 			}
    110 			if (delta.tv_sec < 0) {
    111 				errno = ETIMEDOUT;
    112 				return -1;
    113 			}
    114 			errno = 0;
    115 			r = select(conn->sd + 1, NULL, &writefds, NULL, &delta);
    116 			if (r == -1) {
    117 				if (errno == EINTR)
    118 					continue;
    119 				return -1;
    120 			}
    121 		}
    122 		errno = 0;
    123 		if (conn->ssl != NULL)
    124 			len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
    125 		else
    126 			len = writev(conn->sd, iov, iovcnt);
    127 		if (len == 0) {
    128 			/* we consider a short write a failure */
    129 			/* XXX perhaps we shouldn't in the SSL case */
    130 			errno = EPIPE;
    131 			return -1;
    132 		}
    133 		if (len < 0) {
    134 			if (errno == EINTR)
    135 				continue;
    136 			return -1;
    137 		}
    138 		total += len;
    139 		while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) {
    140 			len -= iov->iov_len;
    141 			iov++;
    142 			iovcnt--;
    143 		}
    144 		if (iovcnt > 0) {
    145 			iov->iov_len -= len;
    146 			iov->iov_base = (char *)iov->iov_base + len;
    147 		}
    148 	}
    149 	return total;
    150 }
    151 
    152 /*
    153  * Write to a connection w/ timeout
    154  */
    155 static int
    156 fetch_write(struct fetch_connect *conn, const char *str, size_t len)
    157 {
    158 	struct iovec iov[1];
    159 
    160 	iov[0].iov_base = (char *)__UNCONST(str);
    161 	iov[0].iov_len = len;
    162 	return fetch_writev(conn, iov, 1);
    163 }
    164 
    165 /*
    166  * Send a formatted line; optionally echo to terminal
    167  */
    168 int
    169 fetch_printf(struct fetch_connect *conn, const char *fmt, ...)
    170 {
    171 	va_list ap;
    172 	size_t len;
    173 	char *msg;
    174 	int r;
    175 
    176 	va_start(ap, fmt);
    177 	len = vasprintf(&msg, fmt, ap);
    178 	va_end(ap);
    179 
    180 	if (msg == NULL) {
    181 		errno = ENOMEM;
    182 		return -1;
    183 	}
    184 
    185 	r = fetch_write(conn, msg, len);
    186 	free(msg);
    187 	return r;
    188 }
    189 
    190 int
    191 fetch_fileno(struct fetch_connect *conn)
    192 {
    193 
    194 	return conn->sd;
    195 }
    196 
    197 int
    198 fetch_error(struct fetch_connect *conn)
    199 {
    200 
    201 	return conn->iserr;
    202 }
    203 
    204 static void
    205 fetch_clearerr(struct fetch_connect *conn)
    206 {
    207 
    208 	conn->iserr = 0;
    209 }
    210 
    211 int
    212 fetch_flush(struct fetch_connect *conn)
    213 {
    214 	int v;
    215 
    216 	if (conn->issock) {
    217 #ifdef TCP_NOPUSH
    218 		v = 0;
    219 		setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v));
    220 #endif
    221 		v = 1;
    222 		setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
    223 	}
    224 	return 0;
    225 }
    226 
    227 /*ARGSUSED*/
    228 struct fetch_connect *
    229 fetch_open(const char *fname, const char *fmode)
    230 {
    231 	struct fetch_connect *conn;
    232 	int fd;
    233 
    234 	fd = open(fname, O_RDONLY); /* XXX: fmode */
    235 	if (fd < 0)
    236 		return NULL;
    237 
    238 	if ((conn = calloc(1, sizeof(*conn))) == NULL) {
    239 		close(fd);
    240 		return NULL;
    241 	}
    242 
    243 	conn->sd = fd;
    244 	conn->issock = 0;
    245 	return conn;
    246 }
    247 
    248 /*ARGSUSED*/
    249 struct fetch_connect *
    250 fetch_fdopen(int sd, const char *fmode)
    251 {
    252 	struct fetch_connect *conn;
    253 #if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH)
    254 	int opt = 1;
    255 #endif
    256 
    257 	if ((conn = calloc(1, sizeof(*conn))) == NULL)
    258 		return NULL;
    259 
    260 	conn->sd = sd;
    261 	conn->issock = 1;
    262 	fcntl(sd, F_SETFD, FD_CLOEXEC);
    263 #ifdef SO_NOSIGPIPE
    264 	setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
    265 #endif
    266 #ifdef TCP_NOPUSH
    267 	setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt));
    268 #endif
    269 	return conn;
    270 }
    271 
    272 int
    273 fetch_close(struct fetch_connect *conn)
    274 {
    275 	int rv = 0;
    276 
    277 	if (conn != NULL) {
    278 		fetch_flush(conn);
    279 		SSL_free(conn->ssl);
    280 		rv = close(conn->sd);
    281 		if (rv < 0) {
    282 			errno = rv;
    283 			rv = EOF;
    284 		}
    285 		free(conn->cache.buf);
    286 		free(conn->buf);
    287 		free(conn);
    288 	}
    289 	return rv;
    290 }
    291 
    292 #define FETCH_READ_WAIT		-2
    293 #define FETCH_READ_ERROR	-1
    294 
    295 static ssize_t
    296 fetch_ssl_read(SSL *ssl, void *buf, size_t len)
    297 {
    298 	ssize_t rlen;
    299 	int ssl_err;
    300 
    301 	rlen = SSL_read(ssl, buf, len);
    302 	if (rlen < 0) {
    303 		ssl_err = SSL_get_error(ssl, rlen);
    304 		if (ssl_err == SSL_ERROR_WANT_READ ||
    305 		    ssl_err == SSL_ERROR_WANT_WRITE) {
    306 			return FETCH_READ_WAIT;
    307 		}
    308 		ERR_print_errors_fp(ttyout);
    309 		return FETCH_READ_ERROR;
    310 	}
    311 	return rlen;
    312 }
    313 
    314 static ssize_t
    315 fetch_nonssl_read(int sd, void *buf, size_t len)
    316 {
    317 	ssize_t rlen;
    318 
    319 	rlen = read(sd, buf, len);
    320 	if (rlen < 0) {
    321 		if (errno == EAGAIN || errno == EINTR)
    322 			return FETCH_READ_WAIT;
    323 		return FETCH_READ_ERROR;
    324 	}
    325 	return rlen;
    326 }
    327 
    328 /*
    329  * Cache some data that was read from a socket but cannot be immediately
    330  * returned because of an interrupted system call.
    331  */
    332 static int
    333 fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes)
    334 {
    335 
    336 	if (conn->cache.size < nbytes) {
    337 		char *tmp = realloc(conn->cache.buf, nbytes);
    338 		if (tmp == NULL)
    339 			return -1;
    340 
    341 		conn->cache.buf = tmp;
    342 		conn->cache.size = nbytes;
    343 	}
    344 
    345 	memcpy(conn->cache.buf, src, nbytes);
    346 	conn->cache.len = nbytes;
    347 	conn->cache.pos = 0;
    348 	return 0;
    349 }
    350 
    351 size_t
    352 fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
    353 {
    354 	struct timeval now, timeout, delta;
    355 	fd_set readfds;
    356 	ssize_t rlen, total;
    357 	size_t len;
    358 	char *start, *buf;
    359 
    360 	if (quit_time > 0) {
    361 		gettimeofday(&timeout, NULL);
    362 		timeout.tv_sec += quit_time;
    363 	}
    364 
    365 	total = 0;
    366 	start = buf = ptr;
    367 	len = size * nmemb;
    368 
    369 	if (conn->cache.len > 0) {
    370 		/*
    371 		 * The last invocation of fetch_read was interrupted by a
    372 		 * signal after some data had been read from the socket. Copy
    373 		 * the cached data into the supplied buffer before trying to
    374 		 * read from the socket again.
    375 		 */
    376 		total = (conn->cache.len < len) ? conn->cache.len : len;
    377 		memcpy(buf, conn->cache.buf, total);
    378 
    379 		conn->cache.len -= total;
    380 		conn->cache.pos += total;
    381 		len -= total;
    382 		buf += total;
    383 	}
    384 
    385 	while (len > 0) {
    386 		/*
    387 		 * The socket is non-blocking.  Instead of the canonical
    388 		 * select() -> read(), we do the following:
    389 		 *
    390 		 * 1) call read() or SSL_read().
    391 		 * 2) if an error occurred, return -1.
    392 		 * 3) if we received data but we still expect more,
    393 		 *    update our counters and loop.
    394 		 * 4) if read() or SSL_read() signaled EOF, return.
    395 		 * 5) if we did not receive any data but we're not at EOF,
    396 		 *    call select().
    397 		 *
    398 		 * In the SSL case, this is necessary because if we
    399 		 * receive a close notification, we have to call
    400 		 * SSL_read() one additional time after we've read
    401 		 * everything we received.
    402 		 *
    403 		 * In the non-SSL case, it may improve performance (very
    404 		 * slightly) when reading small amounts of data.
    405 		 */
    406 		if (conn->ssl != NULL)
    407 			rlen = fetch_ssl_read(conn->ssl, buf, len);
    408 		else
    409 			rlen = fetch_nonssl_read(conn->sd, buf, len);
    410 		if (rlen == 0) {
    411 			conn->iseof = 1;
    412 			break;
    413 		} else if (rlen > 0) {
    414 			len -= rlen;
    415 			buf += rlen;
    416 			total += rlen;
    417 			continue;
    418 		} else if (rlen == FETCH_READ_ERROR) {
    419 			conn->iserr = errno;
    420 			if (errno == EINTR)
    421 				fetch_cache_data(conn, start, total);
    422 			return 0;
    423 		}
    424 		FD_ZERO(&readfds);
    425 		while (!FD_ISSET(conn->sd, &readfds)) {
    426 			FD_SET(conn->sd, &readfds);
    427 			if (quit_time > 0) {
    428 				gettimeofday(&now, NULL);
    429 				if (!timercmp(&timeout, &now, >)) {
    430 					conn->iserr = ETIMEDOUT;
    431 					return 0;
    432 				}
    433 				timersub(&timeout, &now, &delta);
    434 			}
    435 			errno = 0;
    436 			if (select(conn->sd + 1, &readfds, NULL, NULL,
    437 				quit_time > 0 ? &delta : NULL) < 0) {
    438 				if (errno == EINTR)
    439 					continue;
    440 				conn->iserr = errno;
    441 				return 0;
    442 			}
    443 		}
    444 	}
    445 	return total;
    446 }
    447 
    448 #define MIN_BUF_SIZE 1024
    449 
    450 /*
    451  * Read a line of text from a connection w/ timeout
    452  */
    453 char *
    454 fetch_getln(char *str, int size, struct fetch_connect *conn)
    455 {
    456 	size_t tmpsize;
    457 	size_t len;
    458 	char c;
    459 
    460 	if (conn->buf == NULL) {
    461 		if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
    462 			errno = ENOMEM;
    463 			conn->iserr = 1;
    464 			return NULL;
    465 		}
    466 		conn->bufsize = MIN_BUF_SIZE;
    467 	}
    468 
    469 	if (conn->iserr || conn->iseof)
    470 		return NULL;
    471 
    472 	if (conn->buflen - conn->bufpos > 0)
    473 		goto done;
    474 
    475 	conn->buf[0] = '\0';
    476 	conn->bufpos = 0;
    477 	conn->buflen = 0;
    478 	do {
    479 		len = fetch_read(&c, sizeof(c), 1, conn);
    480 		if (len == 0) {
    481 			if (conn->iserr)
    482 				return NULL;
    483 			if (conn->iseof)
    484 				break;
    485 			abort();
    486 		}
    487 		conn->buf[conn->buflen++] = c;
    488 		if (conn->buflen == conn->bufsize) {
    489 			char *tmp = conn->buf;
    490 			tmpsize = conn->bufsize * 2 + 1;
    491 			if ((tmp = realloc(tmp, tmpsize)) == NULL) {
    492 				errno = ENOMEM;
    493 				conn->iserr = 1;
    494 				return NULL;
    495 			}
    496 			conn->buf = tmp;
    497 			conn->bufsize = tmpsize;
    498 		}
    499 	} while (c != '\n');
    500 
    501 	if (conn->buflen == 0)
    502 		return NULL;
    503  done:
    504 	tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos));
    505 	memcpy(str, conn->buf + conn->bufpos, tmpsize);
    506 	str[tmpsize] = '\0';
    507 	conn->bufpos += tmpsize;
    508 	return str;
    509 }
    510 
    511 int
    512 fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
    513     const char **errormsg)
    514 {
    515 	size_t len;
    516 	int rv;
    517 
    518 	if (fetch_getln(buf, buflen, conn) == NULL) {
    519 		if (conn->iseof) {	/* EOF */
    520 			rv = -2;
    521 			if (errormsg)
    522 				*errormsg = "\nEOF received";
    523 		} else {		/* error */
    524 			rv = -1;
    525 			if (errormsg)
    526 				*errormsg = "Error encountered";
    527 		}
    528 		fetch_clearerr(conn);
    529 		return rv;
    530 	}
    531 	len = strlen(buf);
    532 	if (buf[len - 1] == '\n') {	/* clear any trailing newline */
    533 		buf[--len] = '\0';
    534 	} else if (len == buflen - 1) {	/* line too long */
    535 		while (1) {
    536 			char c;
    537 			size_t rlen = fetch_read(&c, sizeof(c), 1, conn);
    538 			if (rlen == 0 || c == '\n')
    539 				break;
    540 		}
    541 		if (errormsg)
    542 			*errormsg = "Input line is too long";
    543 		fetch_clearerr(conn);
    544 		return -3;
    545 	}
    546 	if (errormsg)
    547 		*errormsg = NULL;
    548 	return len;
    549 }
    550 
    551 void *
    552 fetch_start_ssl(int sock, const char *servername)
    553 {
    554 	SSL *ssl;
    555 	SSL_CTX *ctx;
    556 	int ret, ssl_err;
    557 
    558 	/* Init the SSL library and context */
    559 	if (!SSL_library_init()){
    560 		fprintf(ttyout, "SSL library init failed\n");
    561 		return NULL;
    562 	}
    563 
    564 	SSL_load_error_strings();
    565 
    566 	ctx = SSL_CTX_new(SSLv23_client_method());
    567 	SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
    568 
    569 	ssl = SSL_new(ctx);
    570 	if (ssl == NULL){
    571 		fprintf(ttyout, "SSL context creation failed\n");
    572 		SSL_CTX_free(ctx);
    573 		return NULL;
    574 	}
    575 	SSL_set_fd(ssl, sock);
    576 	if (!SSL_set_tlsext_host_name(ssl, __UNCONST(servername))) {
    577 		fprintf(ttyout, "SSL hostname setting failed\n");
    578 		SSL_CTX_free(ctx);
    579 		return NULL;
    580 	}
    581 	while ((ret = SSL_connect(ssl)) == -1) {
    582 		ssl_err = SSL_get_error(ssl, ret);
    583 		if (ssl_err != SSL_ERROR_WANT_READ &&
    584 		    ssl_err != SSL_ERROR_WANT_WRITE) {
    585 			ERR_print_errors_fp(ttyout);
    586 			SSL_free(ssl);
    587 			return NULL;
    588 		}
    589 	}
    590 
    591 	if (ftp_debug && verbose) {
    592 		X509 *cert;
    593 		X509_NAME *name;
    594 		char *str;
    595 
    596 		fprintf(ttyout, "SSL connection established using %s\n",
    597 		    SSL_get_cipher(ssl));
    598 		cert = SSL_get_peer_certificate(ssl);
    599 		name = X509_get_subject_name(cert);
    600 		str = X509_NAME_oneline(name, 0, 0);
    601 		fprintf(ttyout, "Certificate subject: %s\n", str);
    602 		free(str);
    603 		name = X509_get_issuer_name(cert);
    604 		str = X509_NAME_oneline(name, 0, 0);
    605 		fprintf(ttyout, "Certificate issuer: %s\n", str);
    606 		free(str);
    607 	}
    608 
    609 	return ssl;
    610 }
    611 
    612 
    613 void
    614 fetch_set_ssl(struct fetch_connect *conn, void *ssl)
    615 {
    616 	conn->ssl = ssl;
    617 }
    618