added minimal ssl support

Sat, 31 Oct 2015 15:01:07 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 31 Oct 2015 15:01:07 +0100
changeset 106
b122f34ddc80
parent 105
63d9051fe35c
child 107
7e81699d1f77

added minimal ssl support

src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/httplistener.c file | annotate | diff | comparison | revisions
src/server/daemon/httplistener.h file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.h file | annotate | diff | comparison | revisions
src/server/daemon/webserver.c file | annotate | diff | comparison | revisions
src/server/daemon/webserver.h file | annotate | diff | comparison | revisions
src/server/util/io.c file | annotate | diff | comparison | revisions
src/server/util/io.h file | annotate | diff | comparison | revisions
src/server/util/systems.h file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
src/server/util/util.h file | annotate | diff | comparison | revisions
--- 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;
+}
--- 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
 }
--- 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 */
         
--- 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 <openssl/bio.h> 
+#include <openssl/ssl.h> 
+#include <openssl/err.h> 
 
 #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);
--- 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;
--- 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) {
--- 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 <openssl/bio.h> 
+#include <openssl/ssl.h> 
+#include <openssl/err.h> 
+
 #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();
 
--- 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 <sys/types.h>
 #include <sys/stat.h>
 
+#include <openssl/bio.h> 
+#include <openssl/ssl.h> 
+#include <openssl/err.h> 
+
 #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;
+}
--- 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
--- 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;i<iovcnt;i++) {
+        int ret = SSL_write(st->ssl, 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) {
--- 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 <openssl/ssl.h> 
+
 #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);
--- 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 --- */
--- 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 ------------------------------- */
 /*
--- 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);

mercurial