Main Page | Modules | File List | Globals

iossl.c

00001 /*
00002  * Copyright (c) 2005, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: iossl.c,v 1.20 2008/04/21 17:04:18 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <unistd.h>
00013 #include <klone/io.h>
00014 #include <klone/ioprv.h>
00015 #include <u/libu.h>
00016 #include <openssl/ssl.h>
00017 #include <openssl/err.h>
00018 
00019 struct io_ssl_s
00020 {
00021     struct io_s io; /* must be the first item */
00022     SSL *ssl;
00023     int fd;
00024     int flags;
00025 };
00026 
00027 typedef struct io_ssl_s io_ssl_t;
00028 
00029 static ssize_t io_ssl_read(io_ssl_t *io, char *buf, size_t size);
00030 static ssize_t io_ssl_write(io_ssl_t *io, const char *buf, size_t size);
00031 
00032 int io_ssl_get_SSL(io_t *io, SSL **pssl)
00033 {
00034     io_ssl_t *io_ssl = (io_ssl_t*)io;
00035 
00036     dbg_err_if(io_ssl == NULL);
00037     dbg_err_if(pssl == NULL);
00038     dbg_err_if(io_ssl->io.type != IO_TYPE_SSL);
00039 
00040     dbg_err_if(io_ssl->ssl == NULL);
00041 
00042     *pssl = io_ssl->ssl;
00043 
00044     return 0;
00045 err:
00046     return ~0;
00047 }
00048 
00049 static ssize_t io_ssl_read(io_ssl_t *io_ssl, char *buf, size_t size)
00050 {
00051     ssize_t c;
00052 
00053     dbg_err_if (io_ssl == NULL);
00054     dbg_err_if (buf == NULL);
00055 
00056 again:
00057     c = SSL_read(io_ssl->ssl, buf, size);
00058     /* if(c < 0 && (errno == EINTR || errno == EAGAIN)) */
00059     if(c < 0 && errno == EINTR)
00060         goto again; 
00061 
00062     dbg_err_if(c < 0); 
00063 
00064     return c;
00065 err:
00066     return -1;
00067 }
00068 
00069 static ssize_t io_ssl_write(io_ssl_t *io_ssl, const char *buf, size_t size)
00070 {
00071     ssize_t c;
00072 
00073     dbg_err_if (io_ssl == NULL);
00074     dbg_err_if (buf == NULL);
00075 
00076 again:
00077     c = SSL_write(io_ssl->ssl, buf, size);
00078     /* if(c < 0 && (errno == EINTR || errno == EAGAIN)) */
00079     if(c < 0 && errno == EINTR)
00080         goto again; 
00081 
00082     dbg_err_if(c < 0); 
00083 
00084     return c;
00085 err:
00086     return -1;
00087 }
00088 
00089 /* close the underlaying fd (may be called more then once) */
00090 static int io_ssl_close(io_ssl_t *io_ssl)
00091 {
00092     dbg_err_if(io_ssl == NULL);
00093 
00094     if(io_ssl->flags & IO_FD_CLOSE && io_ssl->fd != -1)
00095     {
00096         close(io_ssl->fd);
00097         io_ssl->fd = -1;
00098     }
00099 
00100     return 0;
00101 err:
00102     return ~0;
00103 }
00104 
00105 /* free data alloc'ed by this io type */
00106 static int io_ssl_free(io_ssl_t *io_ssl)
00107 {
00108     dbg_err_if(io_ssl == NULL);
00109 
00110     dbg_if(io_ssl_close(io_ssl));
00111 
00112     if(io_ssl->ssl)
00113     {
00114         SSL_free(io_ssl->ssl);
00115         io_ssl->ssl = NULL;
00116     }
00117 
00118     return 0;
00119 err:
00120     return -1;
00121 }
00122 
00123 static int io_ssl_connect(io_ssl_t *io_ssl)
00124 {
00125     int rc;
00126 
00127     /* accept a SSL connection */
00128     while((rc = SSL_connect(io_ssl->ssl)) <= 0)
00129     {
00130         /* will return 1 if accept has been blocked by a signal or async IO */
00131         if(BIO_sock_should_retry(rc))
00132             continue;
00133 
00134         if(SSL_get_error(io_ssl->ssl, rc) == SSL_ERROR_WANT_READ)
00135             break; 
00136 
00137         warn_err("SSL accept error: %d", SSL_get_error(io_ssl->ssl, rc));
00138     }
00139 
00140     return 0;
00141 err:
00142     return ~0;
00143 }
00144 
00145 static int io_ssl_accept(io_ssl_t *io_ssl)
00146 {
00147     int rc;
00148 
00149     /* accept a SSL connection */
00150     while((rc = SSL_accept(io_ssl->ssl)) <= 0)
00151     {
00152         /* will return 1 if accept has been blocked by a signal or async IO */
00153         if(BIO_sock_should_retry(rc))
00154             continue;
00155 
00156         if(SSL_get_error(io_ssl->ssl, rc) == SSL_ERROR_WANT_READ)
00157             break; 
00158 
00159         warn_err("SSL accept error: %d", SSL_get_error(io_ssl->ssl, rc));
00160     }
00161 
00162     return 0;
00163 err:
00164     return ~0;
00165 }
00166 
00167 int io_ssl_create(int fd, int flags, int client_mode, 
00168         SSL_CTX *ssl_ctx, io_t **pio)
00169 {
00170     io_ssl_t *io_ssl = NULL;
00171     int rc = 0;
00172     long vfy;
00173 
00174     dbg_return_if (pio == NULL, ~0);
00175     dbg_return_if (ssl_ctx == NULL, ~0);
00176 
00177     dbg_err_if(io_create(io_ssl_t, (io_t**)&io_ssl));
00178 
00179     io_ssl->io.type = IO_TYPE_SSL;
00180 
00181     io_ssl->fd = fd;
00182     io_ssl->flags = flags;
00183 
00184     io_ssl->ssl = SSL_new(ssl_ctx);
00185     dbg_err_if(io_ssl->ssl == NULL);
00186 
00187     /* assign a working descriptor to the SSL stream */
00188     dbg_err_if(SSL_set_fd(io_ssl->ssl, fd) == 0);
00189 
00190     io_ssl->io.read = (io_read_op) io_ssl_read;
00191     io_ssl->io.write = (io_write_op) io_ssl_write;
00192     io_ssl->io.close = (io_close_op) io_ssl_close; 
00193     io_ssl->io.free = (io_free_op) io_ssl_free; 
00194     io_ssl->io.size = 0;
00195 
00196     /* set the secure flag (encrypted connection) */
00197     io_ssl->io.is_secure = 1;
00198     
00199     /* wait for the peer to start the TLS handshake */
00200     if(client_mode)
00201         dbg_err_if(io_ssl_connect(io_ssl));
00202     else
00203         dbg_err_if(io_ssl_accept(io_ssl));
00204 
00205     *pio = (io_t*)io_ssl;
00206 
00207     return 0;
00208 err:
00209     if(io_ssl && io_ssl->ssl)
00210     {
00211         /* print a warning message for bad client certificates */
00212         if((vfy = SSL_get_verify_result(io_ssl->ssl)) != X509_V_OK)
00213             warn("SSL client cert verify error: %s", 
00214                 X509_verify_cert_error_string(vfy));
00215         SSL_set_shutdown(io_ssl->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
00216     }
00217     if(io_ssl)
00218         io_free((io_t *)io_ssl);
00219     return ~0;
00220 }
00221