"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/src/ssl.c" (4 Jul 2020, 13947 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ssl.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

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