Annotation of embedaddon/libpdel/io/ssl_fp.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (c) 2001-2002 Packet Design, LLC.
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Subject to the following obligations and disclaimer of warranty,
                      7:  * use and redistribution of this software, in source or object code
                      8:  * forms, with or without modifications are expressly permitted by
                      9:  * Packet Design; provided, however, that:
                     10:  * 
                     11:  *    (i)  Any and all reproductions of the source or object code
                     12:  *         must include the copyright notice above and the following
                     13:  *         disclaimer of warranties; and
                     14:  *    (ii) No rights are granted, in any manner or form, to use
                     15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
                     16:  *         on advertising, endorsements, or otherwise except as such
                     17:  *         appears in the above copyright notice or in the software.
                     18:  * 
                     19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
                     20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
                     21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
                     22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
                     24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
                     25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
                     26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
                     27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
                     28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
                     29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
                     30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
                     31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
                     32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
                     33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
                     35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
                     36:  * THE POSSIBILITY OF SUCH DAMAGE.
                     37:  *
                     38:  * Author: Archie Cobbs <archie@freebsd.org>
                     39:  */
                     40: 
                     41: #include <sys/param.h>
                     42: #include <sys/syslog.h>
                     43: 
                     44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <stdarg.h>
                     47: #include <string.h>
                     48: #include <unistd.h>
                     49: #include <fcntl.h>
                     50: #include <errno.h>
                     51: #include <poll.h>
                     52: #include <pthread.h>
                     53: 
                     54: #include <openssl/ssl.h>
                     55: #include <openssl/err.h>
                     56: 
                     57: #include "structs/structs.h"
                     58: #include "structs/type/array.h"
                     59: 
                     60: #include "util/typed_mem.h"
                     61: #include "io/ssl_fp.h"
                     62: 
                     63: struct ssl_info {
                     64:        int                     fd;
                     65:        SSL                     *ssl;
                     66:        SSL_CTX                 *ssl_ctx;
                     67:        int                     error;
                     68:        u_char                  server;
                     69:        ssl_logger_t            *logger;
                     70:        void                    *logarg;
                     71:        const char              *mtype;
                     72:        u_int                   timeout;
                     73: };
                     74: 
                     75: /*
                     76:  * Internal functions
                     77:  */
                     78: static int     ssl_read(void *cookie, char *buf, int len);
                     79: static int     ssl_write(void *cookie, const char *buf, int len);
                     80: static int     ssl_close(void *cookie);
                     81: static int     ssl_check(struct ssl_info *s);
                     82: static int     ssl_err(struct ssl_info *s, int ret);
                     83: 
                     84: static ssl_logger_t    null_logger;
                     85: 
                     86: /*
                     87:  * Create a FILE * from an SSL connection.
                     88:  */
                     89: FILE *
                     90: ssl_fdopen(SSL_CTX *ssl_ctx, int fd, int server, const char *mtype,
                     91:        ssl_logger_t *logger, void *logarg, u_int timeout)
                     92: {
                     93:        struct ssl_info *s;
                     94:        int flags;
                     95:        FILE *fp;
                     96: 
                     97:        /* Create SSL info */
                     98:        if ((s = MALLOC(mtype, sizeof(*s))) == NULL)
                     99:                return (NULL);
                    100:        memset(s, 0, sizeof(*s));
                    101:        s->fd = fd;
                    102:        s->ssl_ctx = ssl_ctx;
                    103:        s->mtype = mtype;
                    104:        s->server = !!server;
                    105:        s->logger = (logger != NULL) ? logger : null_logger;
                    106:        s->logarg = logarg;
                    107:        s->timeout = timeout;
                    108: 
                    109:        /* Set fd I/O to non-blocking */
                    110:        if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
                    111:                FREE(mtype, s);
                    112:                return (NULL);
                    113:        }
                    114: #if 0
                    115:        if ((flags & O_NONBLOCK) == 0
                    116:            && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
                    117:                FREE(mtype, s);
                    118:                return (NULL);
                    119:        }
                    120: #endif
                    121: 
                    122:        /* Create FILE * stream */
                    123:        if ((fp = funopen(s, ssl_read, ssl_write, NULL, ssl_close)) == NULL) {
                    124:                (void)fcntl(fd, F_SETFL, flags);
                    125:                FREE(mtype, s);
                    126:                return (NULL);
                    127:        }
                    128: 
                    129:        /* Done */
                    130:        return (fp);
                    131: }
                    132: 
                    133: /*
                    134:  * Read from an SSL connection.
                    135:  */
                    136: static int
                    137: ssl_read(void *cookie, char *buf, int len)
                    138: {
                    139:        struct ssl_info *const s = cookie;
                    140:        int ret;
                    141: 
                    142:        /* Check connection */
                    143:        if (ssl_check(s) == -1)
                    144:                return (-1);
                    145: 
                    146: tryread:
                    147:        /* Try to read some more data */
                    148:        if ((ret = SSL_read(s->ssl, buf, len)) <= 0) {
                    149:                if (ssl_err(s, ret) == -1)
                    150:                        return (-1);
                    151:                goto tryread;
                    152:        }
                    153:        return (ret);
                    154: }
                    155: 
                    156: /*
                    157:  * Write to an SSL connection.
                    158:  */
                    159: static int
                    160: ssl_write(void *cookie, const char *buf, int len)
                    161: {
                    162:        struct ssl_info *const s = cookie;
                    163:        int ret;
                    164: 
                    165:        /* Check connection */
                    166:        if (ssl_check(s) == -1)
                    167:                return (-1);
                    168: 
                    169: trywrite:
                    170:        /* Try to write some more data */
                    171:        if ((ret = SSL_write(s->ssl, buf, len)) <= 0) {
                    172:                if (ssl_err(s, ret) == -1)
                    173:                        return (-1);
                    174:                goto trywrite;
                    175:        }
                    176:        return (ret);
                    177: }
                    178: 
                    179: /*
                    180:  * Close an SSL connection.
                    181:  */
                    182: static int
                    183: ssl_close(void *cookie)
                    184: {
                    185:        struct ssl_info *const s = cookie;
                    186:        int ret;
                    187: 
                    188:        while ((ret = SSL_shutdown(s->ssl)) <= 0) {
                    189:                if (ret == -1 && ssl_err(s, ret) == -1) {
                    190:                        (void)close(s->fd);
                    191:                        return (-1);
                    192:                }
                    193:        }
                    194:        (void)close(s->fd);
                    195:        SSL_free(s->ssl);
                    196:        FREE(s->mtype, s);
                    197:        return (0);
                    198: }
                    199: 
                    200: /*
                    201:  * Check SSL connection context.
                    202:  */
                    203: static int
                    204: ssl_check(struct ssl_info *s)
                    205: {
                    206:        int ret;
                    207: 
                    208:        /* Check for previous error */
                    209:        if (s->error != 0)
                    210:                goto fail;
                    211: 
                    212:        /* Already set up SSL? */
                    213:        if (s->ssl != NULL)
                    214:                return (0);
                    215: 
                    216:        /* Create ssl connection context */
                    217:        if ((s->ssl = SSL_new(s->ssl_ctx)) == NULL) {
                    218:                ssl_log(s->logger, s->logarg);
                    219:                s->error = ECONNABORTED;
                    220:                goto fail;
                    221:        }
                    222:        SSL_set_fd(s->ssl, s->fd);
                    223: 
                    224:        /* Do initial SSL handshake */
                    225:        if (s->server) {
                    226:                while ((ret = SSL_accept(s->ssl)) <= 0) {
                    227:                        if (ssl_err(s, ret) == -1)
                    228:                                goto fail;
                    229:                }
                    230:        } else {
                    231:                while ((ret = SSL_connect(s->ssl)) <= 0) {
                    232:                        if (ssl_err(s, ret) == -1)
                    233:                                goto fail;
                    234:                }
                    235:        }
                    236: 
                    237:        /* Ready */
                    238:        return (0);
                    239: 
                    240: fail:
                    241:        /* Failed */
                    242:        errno = s->error;
                    243:        return (-1);
                    244: }
                    245: 
                    246: /*
                    247:  * Handle an error return from an SSL I/O operation.
                    248:  *
                    249:  * It might be an error, or it might just be that more raw data
                    250:  * needs to be read or written. Return -1 in the former case,
                    251:  * otherwise return zero and wait for the readable or writable
                    252:  * event as appropriate.
                    253:  */
                    254: static int
                    255: ssl_err(struct ssl_info *s, int ret)
                    256: {
                    257:        int ret2;
                    258: 
                    259:        ret2 = SSL_get_error(s->ssl, ret);
                    260:        switch (ret2) {
                    261:        case SSL_ERROR_WANT_READ:
                    262:        case SSL_ERROR_WANT_WRITE:
                    263:            {
                    264:                struct pollfd pfd;
                    265:                int timeout;
                    266:                int nfds;
                    267: 
                    268:                /* Set up read/write poll(2) event */
                    269:                memset(&pfd, 0, sizeof(pfd));
                    270:                pfd.fd = s->fd;
                    271:                pfd.events = (ret2 == SSL_ERROR_WANT_READ) ?
                    272:                    POLLRDNORM : POLLWRNORM;
                    273: 
                    274:                /* Set up timeout */
                    275:                timeout = INFTIM;
                    276:                if (s->timeout != 0)
                    277:                        timeout = s->timeout * 1000;
                    278: 
                    279:                /* Wait for readability or writability */
                    280:                if ((nfds = poll(&pfd, 1, timeout)) == -1) {
                    281:                        s->error = errno;
                    282:                        (*s->logger)(s->logarg, LOG_ERR,
                    283:                            "%s: %s", "poll", strerror(errno));
                    284:                        goto fail;
                    285:                }
                    286: 
                    287:                /* Check for timeout */
                    288:                if (nfds == 0) {
                    289:                        s->error = ETIMEDOUT;
                    290:                        goto fail;
                    291:                }
                    292: 
                    293:                /* Done */
                    294:                return (0);
                    295:            }
                    296:        case SSL_ERROR_NONE:
                    297:                return (0);
                    298: 
                    299:        case SSL_ERROR_SYSCALL:
                    300:                ssl_log(s->logger, s->logarg);
                    301:                if (ret != 0) {
                    302:                        s->error = errno;
                    303:                        (*s->logger)(s->logarg, LOG_ERR,
                    304:                            "SSL system error: %s", strerror(errno));
                    305:                        goto fail;
                    306:                }
                    307:                /* fall through */
                    308: 
                    309:        case SSL_ERROR_ZERO_RETURN:
                    310:                (*s->logger)(s->logarg, LOG_ERR, "SSL connection closed");
                    311:                s->error = ECONNRESET;
                    312:                goto fail;
                    313: 
                    314:        case SSL_ERROR_SSL:
                    315:                ssl_log(s->logger, s->logarg);
                    316:                s->error = EIO;
                    317:                goto fail;
                    318: 
                    319:        case SSL_ERROR_WANT_X509_LOOKUP:                /* should not happen */
                    320:        default:
                    321:                ssl_log(s->logger, s->logarg);
                    322:                (*s->logger)(s->logarg, LOG_ERR,
                    323:                    "unknown return %d from SSL_get_error", ret2);
                    324:                s->error = ECONNABORTED;
                    325:                goto fail;
                    326:        }
                    327: 
                    328: fail:
                    329:        /* Got an error */
                    330:        errno = s->error;
                    331:        return (-1);
                    332: }
                    333: 
                    334: /*
                    335:  * Log an SSL error.
                    336:  */
                    337: void
                    338: ssl_log(ssl_logger_t *logger, void *logarg)
                    339: {
                    340:        char buf[200];
                    341:        const char *file;
                    342:        const char *str;
                    343:        const char *t;
                    344:        int line, flags;
                    345:        u_long e;
                    346: 
                    347:        while ((e = ERR_get_error_line_data(&file, &line, &str, &flags)) != 0) {
                    348:                if (logger == NULL)
                    349:                        continue;
                    350: #if 0
                    351:                (*logger)(logarg, LOG_ERR, "SSL: %s:%s:%d:%s\n",
                    352:                    ERR_error_string(e, buf), file, line,
                    353:                    (flags & ERR_TXT_STRING) ? str : "");
                    354: #else
                    355:                strlcpy(buf, "SSL: ", sizeof(buf));
                    356: #if 0
                    357:                /* Add library */
                    358:                if ((t = ERR_lib_error_string(e)) != NULL) {
                    359:                        strlcat(buf, t, sizeof(buf));
                    360:                        strlcat(buf, ": ", sizeof(buf));
                    361:                } else {
                    362:                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
                    363:                            "lib=%u: ", ERR_GET_LIB(e));
                    364:                }
                    365: #endif
                    366: 
                    367:                /* Add function */
                    368:                if ((t = ERR_func_error_string(e)) != NULL) {
                    369:                        strlcat(buf, t, sizeof(buf));
                    370:                        strlcat(buf, ": ", sizeof(buf));
                    371:                } else {
                    372:                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
                    373:                            "func=%u: ", ERR_GET_FUNC(e));
                    374:                }
                    375: 
                    376:                /* Add reason */
                    377:                if ((t = ERR_reason_error_string(e)) != NULL) {
                    378:                        strlcat(buf, t, sizeof(buf));
                    379:                } else {
                    380:                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
                    381:                            "reason=%u", ERR_GET_REASON(e));
                    382:                }
                    383: 
                    384:                /* Add error text, if any */
                    385:                if ((flags & ERR_TXT_STRING) != 0) {
                    386:                        strlcat(buf, ": ", sizeof(buf));
                    387:                        strlcat(buf, str, sizeof(buf));
                    388:                }
                    389:                (*logger)(logarg, LOG_ERR, "%s", buf);
                    390: #endif
                    391:        }
                    392: }
                    393: 
                    394: static void
                    395: null_logger(void *arg, int sev, const char *fmt, ...)
                    396: {
                    397:        return;
                    398: }
                    399: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>