# HG changeset patch # User Olaf Wintermann # Date 1446300067 -3600 # Node ID b122f34ddc809f04589e37dd2a0b85662266634e # Parent 63d9051fe35caf2d65f690494d8dd0454f8bfb36 added minimal ssl support diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/config.c --- a/src/server/daemon/config.c Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/config.c Sat Oct 31 15:01:07 2015 +0100 @@ -53,6 +53,7 @@ #include "../util/pblock.h" #include "../util/util.h" #include "../util/atomic.h" +#include "ucx/buffer.h" pool_handle_t *cfg_pool; @@ -575,6 +576,29 @@ obj->directives, sstr("Threadpool"))); + sstr_t ssl = cfg_directivelist_get_str(obj->directives, S("SSL")); + if(util_getboolean_s(ssl, WS_FALSE)) { + sstr_t cert = cfg_directivelist_get_str(obj->directives, S("Cert")); + sstr_t privkey = cfg_directivelist_get_str(obj->directives, S("PrivateKey")); + sstr_t chain = cfg_directivelist_get_str(obj->directives, S("Chain")); + WSBool config_ok = WS_TRUE; + // TODO: log error + if(!cert.ptr) { + config_ok = WS_FALSE; + } + if(!privkey.ptr) { + config_ok = WS_FALSE; + } + if(config_ok) { + lc.certfile = cert; + lc.privkeyfile = privkey; + lc.chainfile = chain; + lc.ssl = WS_TRUE; + } + } else { + lc.ssl = WS_FALSE; + } + // TODO: check if all important configs are set HttpListener *listener = http_listener_create(&lc); @@ -955,3 +979,40 @@ return 0; } + + +sstr_t cfg_load_file(sstr_t file) { + sstr_t r; + r.ptr = NULL; + r.length = 0; + + if(!file.ptr) { + return r; + } + + sstr_t f = sstrdup(file); + FILE *in = fopen(f.ptr, "r"); + if(!in) { + return r; + } + + UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); + if(!buf) { + fclose(in); + return r; + } + + if(ucx_stream_hcopy(in, buf, (read_func)fread, (write_func)ucx_buffer_write) == 0) { + fclose(in); + ucx_buffer_free(buf); + return r; + } + + r.ptr = buf->space; + r.length = buf->pos; + + free(buf); + fclose(in); + + return r; +} diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/config.h --- a/src/server/daemon/config.h Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/config.h Sat Oct 31 15:01:07 2015 +0100 @@ -121,7 +121,7 @@ ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl); int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg); - +sstr_t cfg_load_file(sstr_t file); #ifdef __cplusplus } diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/httplistener.c --- a/src/server/daemon/httplistener.c Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/httplistener.c Sat Oct 31 15:01:07 2015 +0100 @@ -159,6 +159,34 @@ listener->port = conf->port; listener->ref = 1; listener->next = NULL; + listener->ssl = NULL; + if(conf->ssl) { + listener->ssl = malloc(sizeof(HttpSSL)); + + SSL_CTX *ctx = SSL_CTX_new( SSLv23_server_method()); + SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); + + sstr_t file = sstrdup(conf->certfile); + int ret = SSL_CTX_use_certificate_file(ctx, file.ptr, SSL_FILETYPE_PEM); + free(file.ptr); + if(!ret) { + // TODO: cleanup + return NULL; + } + + file = sstrdup(conf->privkeyfile); + ret = SSL_CTX_use_PrivateKey_file(ctx, file.ptr, SSL_FILETYPE_PEM); + free(file.ptr); + if(!ret) { + // TODO: cleanup + return NULL; + } + + // TODO: chain + listener->ssl->sslctx = ctx; + } + + ucx_map_sstr_put(listener_map, listener->name, listener); struct sockaddr_in servaddr; /* server address */ @@ -288,13 +316,32 @@ conn->address = ca; conn->fd = clientfd; conn->listener = ls; + if(ls->ssl) { + SSL *ssl = SSL_new(ls->ssl->sslctx); + SSL_set_fd(ssl, clientfd); + if(SSL_accept(ssl) <= 0) { + free(conn); + conn = NULL; + } else { + conn->ssl = ssl; + conn->read = connection_ssl_read; + conn->write = connection_ssl_write; + conn->close = connection_ssl_close; + } + } else { + conn->read = connection_read; + conn->write = connection_write; + conn->close = connection_close; + } - cfg_ref(ls->cfg); + if(conn) { + cfg_ref(ls->cfg); - /* enqueue the connection */ - ls->session_handler->enqueue_connection( - ls->session_handler, - conn); + /* enqueue the connection */ + ls->session_handler->enqueue_connection( + ls->session_handler, + conn); + } /* ready for new connection */ diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/httplistener.h --- a/src/server/daemon/httplistener.h Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/httplistener.h Sat Oct 31 15:01:07 2015 +0100 @@ -32,6 +32,11 @@ #include "sessionhandler.h" #include "threadpools.h" #include "config.h" +#include "../util/systems.h" + +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -40,6 +45,9 @@ /* HttpListener typedef in nsapi.h */ typedef struct _acceptor Acceptor; typedef struct _listener_config ListenerConfig; +typedef struct _http_ssl HttpSSL; + + union vs { @@ -54,6 +62,10 @@ char *address; int port; int nacceptors; + WSBool ssl; + sstr_t certfile; + sstr_t privkeyfile; + sstr_t chainfile; }; struct _acceptor { @@ -73,9 +85,23 @@ Acceptor **acceptors; int nacceptors; int running; + HttpSSL *ssl; uint32_t ref; // reference counter }; +struct _http_ssl { + unsigned char *cert; + size_t certlen; + unsigned char *privkey; + size_t privkeylen; + unsigned char *chain; + size_t chainlen; + + SSL_CTX *sslctx; + + // TODO: ssl/tls cipher, ... config +}; + int start_all_listener(); HttpListener* http_listener_create(ListenerConfig *conf); diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/httprequest.c --- a/src/server/daemon/httprequest.c Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/httprequest.c Sat Oct 31 15:01:07 2015 +0100 @@ -108,7 +108,14 @@ sn->netbuf = request->netbuf; sn->sn.pool = pool; //sn->sn.csd = stream_new_from_fd(pool, request->connection->fd); - sn->sn.csd = net_stream_from_fd(pool, request->connection->fd); + //sn->sn.csd = net_stream_from_fd(pool, request->connection->fd); + if(request->connection->ssl) { + sn->sn.csd = net_ssl_stream(pool, request->connection->ssl); + } else { + sn->sn.csd = net_stream_from_fd(pool, request->connection->fd); + } + + sn->sn.client = pblock_create_pool(sn->sn.pool, 8); sn->sn.next = NULL; sn->sn.fill = 1; diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/sessionhandler.c --- a/src/server/daemon/sessionhandler.c Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/sessionhandler.c Sat Oct 31 15:01:07 2015 +0100 @@ -44,11 +44,37 @@ HttpParser *parser; } EventHttpIO; + +int connection_read(Connection *conn, void *buf, int len) { + return (int)read(conn->fd, buf, len); +} + +int connection_write(Connection *conn, const void *buf, int len) { + return (int)write(conn->fd, buf, len); +} + +void connection_close(Connection *conn) { + close(conn->fd); +} + +int connection_ssl_read(Connection *conn, void *buf, int len) { + return SSL_read(conn->ssl, buf, len); +} + +int connection_ssl_write(Connection *conn, const void *buf, int len) { + return SSL_write(conn->ssl, buf, len); +} + +void connection_ssl_close(Connection *conn) { + SSL_shutdown(conn->ssl); + close(conn->fd); +} + SessionHandler* create_basic_session_handler() { BasicSessionHandler *handler = malloc(sizeof(BasicSessionHandler)); handler->threadpool = threadpool_new(4, 8); handler->sh.enqueue_connection = basic_enq_conn; - + handler->sh.keep_alive = basic_keep_alive; return (SessionHandler*)handler; } @@ -81,7 +107,7 @@ HttpParser *parser = http_parser_new(&request); int state; int r; - r = read(conn->fd, buf->inbuf + buf->pos, buf->maxsize - buf->pos); + r = conn->read(conn, buf->inbuf + buf->pos, buf->maxsize - buf->pos); if(r == -1) { // TODO: error handling fprintf(stderr, "%s\n", "Error: Cannot read from socket"); @@ -94,7 +120,7 @@ fprintf(stderr, "%s\n", "Error: Cannot parse http request"); return NULL; } - r = read(conn->fd, buf->inbuf + buf->pos, buf->maxsize - buf->pos); + r = conn->read(conn, buf->inbuf + buf->pos, buf->maxsize - buf->pos); if(r == -1) { // TODO: error handling fprintf(stderr, "%s\n", "Error: Cannot read from socket"); @@ -102,7 +128,7 @@ } buf->cursize += r; } - + // process request r = handle_request(&request, NULL); // TODO: use correct thread pool @@ -190,12 +216,13 @@ EventHttpIO *io = event->cookie; HttpParser *parser = io->parser; HTTPRequest *request = io->request; + Connection *conn = io->request->connection; netbuf *buf = request->netbuf; int state; int r; - r = read( - request->connection->fd, + r = conn->read( + conn, buf->inbuf + buf->pos, buf->maxsize - buf->pos); if(r == -1) { diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/sessionhandler.h --- a/src/server/daemon/sessionhandler.h Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/sessionhandler.h Sat Oct 31 15:01:07 2015 +0100 @@ -33,6 +33,10 @@ #include "../public/nsapi.h" #include "event.h" +#include +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -45,6 +49,10 @@ struct sockaddr_in address; HttpListener *listener; SessionHandler *session_handler; + SSL *ssl; + int (*read)(Connection *conn, void *buf, int len); + int (*write)(Connection *conn, const void *buf, int len); + void (*close)(Connection *conn); }; typedef void(*enqueue_connection_f)(SessionHandler*, Connection*); @@ -93,6 +101,13 @@ * defined in sesionhandler.c */ +int connection_read(Connection *conn, void *buf, int len); +int connection_write(Connection *conn, const void *buf, int len); +void connection_close(Connection *conn); +int connection_ssl_read(Connection *conn, void *buf, int len); +int connection_ssl_write(Connection *conn, const void *buf, int len); +void connection_ssl_close(Connection *conn); + SessionHandler* create_basic_session_handler(); diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/webserver.c --- a/src/server/daemon/webserver.c Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/webserver.c Sat Oct 31 15:01:07 2015 +0100 @@ -38,6 +38,10 @@ #include #include +#include +#include +#include + #include "../public/nsapi.h" #include "../public/auth.h" #include "../util/systhr.h" @@ -60,6 +64,11 @@ // init NSPR systhread_init("webserver"); + // init ssl + if(ws_init_ssl()) { + return -1; + } + // init NSAPI functions func_init(); add_functions(webserver_funcs); @@ -217,3 +226,12 @@ int nsapi_runtime_version() { return 303; } + + +int ws_init_ssl() { + // TODO: handle errors + SSL_load_error_strings(); + SSL_library_init(); + OpenSSL_add_all_algorithms(); + return 0; +} diff -r 63d9051fe35c -r b122f34ddc80 src/server/daemon/webserver.h --- a/src/server/daemon/webserver.h Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/daemon/webserver.h Sat Oct 31 15:01:07 2015 +0100 @@ -48,6 +48,8 @@ void webserver_atrestart(void (*fn)(void *), void *data); +int ws_init_ssl(); + #ifdef __cplusplus } #endif diff -r 63d9051fe35c -r b122f34ddc80 src/server/util/io.c --- a/src/server/util/io.c Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/util/io.c Sat Oct 31 15:01:07 2015 +0100 @@ -61,6 +61,15 @@ (io_finish_f)net_stream_finish }; +IOStream ssl_io_funcs = { + (io_write_f)net_ssl_write, + (io_writev_f)net_ssl_writev, + (io_read_f)net_ssl_read, + NULL, + (io_close_f)net_ssl_close, + (io_finish_f)net_ssl_finish +}; + IOStream* stream_new_from_fd(pool_handle_t *pool, int fd) { SystemIOStream *st = pool_malloc(pool, sizeof(SystemIOStream)); @@ -194,6 +203,44 @@ } +/* ssl stream */ +IOStream* net_ssl_stream(pool_handle_t *pool, SSL *ssl) { + SSLStream *st = pool_malloc(pool, sizeof(SSLStream)); + st->st = ssl_io_funcs; + st->ssl = ssl; + return (IOStream*)st; +} + +ssize_t net_ssl_write(SSLStream *st, void *buf, size_t nbytes) { + return SSL_write(st->ssl, buf, nbytes); +} + +ssize_t net_ssl_writev(SSLStream *st, struct iovec *iovec, int iovcnt) { + ssize_t r = 0; + for(int i=0;issl, iovec[i].iov_base, iovec[i].iov_len); + if(ret <= 0) { + return 0; + } + r += ret; + } + return r; +} + +ssize_t net_ssl_read(SSLStream *st, void *buf, size_t nbytes) { + return SSL_read(st->ssl, buf, nbytes); +} + +void net_ssl_close(SSLStream *st) { + SSL_shutdown(st->ssl); + close(SSL_get_fd(st->ssl)); +} + +void net_ssl_finish(SSLStream *st) { + +} + + ssize_t net_read(SYS_NETFD fd, void *buf, size_t nbytes) { ssize_t r = ((IOStream*)fd)->read(fd, buf, nbytes); if(r == 0) { diff -r 63d9051fe35c -r b122f34ddc80 src/server/util/io.h --- a/src/server/util/io.h Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/util/io.h Sat Oct 31 15:01:07 2015 +0100 @@ -29,6 +29,8 @@ #ifndef IOSTREAM_H #define IOSTREAM_H +#include + #include "../public/nsapi.h" #ifdef __cplusplus @@ -67,6 +69,11 @@ int buffered; } NetIOStream; +typedef struct SSLStream { + IOStream st; + SSL *ssl; +} SSLStream; + /* net_ functions */ ssize_t net_read(SYS_NETFD fd, void *buf, size_t nbytes); @@ -102,6 +109,15 @@ void net_stream_close(NetIOStream *st); void net_stream_finish(NetIOStream *st); +/* ssl stream */ +IOStream* net_ssl_stream(pool_handle_t *pool, SSL *ssl); + +ssize_t net_ssl_write(SSLStream *st, void *buf, size_t nbytes); +ssize_t net_ssl_writev(SSLStream *st, struct iovec *iovec, int iovcnt); +ssize_t net_ssl_read(SSLStream *st, void *buf, size_t nbytes); +void net_ssl_close(SSLStream *st); +void net_ssl_finish(SSLStream *st); + /* iovec buffer */ iovec_buf_t *iovec_buf_create(pool_handle_t *pool); void iovec_buf_write(iovec_buf_t *io, void *buf, size_t nbyte); diff -r 63d9051fe35c -r b122f34ddc80 src/server/util/systems.h --- a/src/server/util/systems.h Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/util/systems.h Sat Oct 31 15:01:07 2015 +0100 @@ -58,6 +58,10 @@ typedef int PRBool; #define PR_TRUE 1 #define PR_FALSE 0 + +typedef int WSBool; +#define WS_TRUE 1 +#define WS_FALSE 0 /* end new types */ /* --- End common definitions for all supported platforms --- */ diff -r 63d9051fe35c -r b122f34ddc80 src/server/util/util.c --- a/src/server/util/util.c Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/util/util.c Sat Oct 31 15:01:07 2015 +0100 @@ -349,6 +349,19 @@ return def; } +int util_getboolean_s(sstr_t s, int def) { + if(s.length == 0) { + return def; + } + if(s.ptr[0] == 'T' || s.ptr[0] == 't') { + return 1; + } + if(s.ptr[0] == 'F' || s.ptr[0] == 'f') { + return 0; + } + return def; +} + /* ------------------------------ util_itoa ------------------------------- */ /* diff -r 63d9051fe35c -r b122f34ddc80 src/server/util/util.h --- a/src/server/util/util.h Wed Oct 28 17:59:34 2015 +0100 +++ b/src/server/util/util.h Sat Oct 31 15:01:07 2015 +0100 @@ -193,6 +193,7 @@ NSAPI_PUBLIC PRBool INTutil_format_http_version(const char *v, int *protv_num, char *buffer, int size); NSAPI_PUBLIC int INTutil_getboolean(const char *v, int def); +int util_getboolean_s(sstr_t s, int def); // TODO //NSAPI_PUBLIC PRIntervalTime INTutil_getinterval(const char *v, PRIntervalTime def);