kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit f2aa206f3bc7cba5faad24913e5063ea6878066d
parent 08a2fff5a5f124da9155942d718e3e5b2de78580
Author: Joris Vink <joris@coders.se>
Date:   Sat, 14 Dec 2013 16:31:07 +0100

Add support for client certificates

Diffstat:
includes/kore.h | 1+
modules/example/module.conf | 14++++++++++----
src/config.c | 25+++++++++++++++++++++++++
src/connection.c | 3++-
src/domain.c | 23++++++++++++++++++++++-
src/kore.c | 8++++++++
6 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/includes/kore.h b/includes/kore.h @@ -199,6 +199,7 @@ struct kore_domain { char *domain; char *certfile; char *certkey; + char *cafile; int accesslog; SSL_CTX *ssl_ctx; TAILQ_HEAD(, kore_module_handle) handlers; diff --git a/modules/example/module.conf b/modules/example/module.conf @@ -81,7 +81,11 @@ ssl_no_compression # # Additionally you can specify the following in a domain configuration: # -# accesslog: File where all requests are logged. +# accesslog +# - File where all requests are logged. +# require_client_cert +# - Asks the client to present a certificate +# matching the CA given to require_client_cert # # Handlers # @@ -132,9 +136,11 @@ domain localhost { } #domain domain.com { -# certfile cert/other/server.crt -# certkey cert/other/server.key -# accesslog /var/log/other_kore_access.log +# certfile cert/other/server.crt +# certkey cert/other/server.key +# accesslog /var/log/other_kore_access.log +# require_client_cert cert/other/ca.crt + # static /css/style.css serve_style_css # static / serve_index # dynamic ^/[a-z0-9_]*$ serve_profile diff --git a/src/config.c b/src/config.c @@ -49,6 +49,7 @@ static int configure_http_keepalive_time(char **); static int configure_validator(char **); static int configure_params(char **); static int configure_validate(char **); +static int configure_require_client_cert(char **); static void domain_sslstart(void); static struct { @@ -73,6 +74,7 @@ static struct { { "accesslog", configure_accesslog }, { "certfile", configure_certfile }, { "certkey", configure_certkey }, + { "require_client_cert", configure_require_client_cert }, { "kore_cb", configure_kore_cb }, { "kore_cb_worker", configure_kore_cb_worker }, { "kore_cb_interval", configure_kore_cb_interval }, @@ -319,6 +321,29 @@ configure_handler(char **argv) } static int +configure_require_client_cert(char **argv) +{ + if (current_domain == NULL) { + printf("missing domain page require_client_cert\n"); + return (KORE_RESULT_ERROR); + } + + if (argv[1] == NULL) { + printf("missing argument for require_client_cert\n"); + return (KORE_RESULT_ERROR); + } + + if (current_domain->cafile != NULL) { + printf("require_client_cert already set for %s\n", + current_domain->domain); + return (KORE_RESULT_ERROR); + } + + current_domain->cafile = kore_strdup(argv[1]); + return (KORE_RESULT_OK); +} + +static int configure_chroot(char **argv) { if (chroot_path != NULL) { diff --git a/src/connection.c b/src/connection.c @@ -141,7 +141,8 @@ kore_connection_handle(struct connection *c) r = SSL_get_verify_result(c->ssl); if (r != X509_V_OK) { - kore_debug("SSL_get_verify_result(): %s", ssl_errno_s); + kore_debug("SSL_get_verify_result(): %d, %s", + r, ssl_errno_s); return (KORE_RESULT_ERROR); } diff --git a/src/domain.c b/src/domain.c @@ -16,6 +16,8 @@ #include "kore.h" +#define SSL_SESSION_ID "kore_ssl_sessionid" + struct kore_domain_h domains; struct kore_domain *primary_dom = NULL; DH *ssl_dhparam = NULL; @@ -39,9 +41,10 @@ kore_domain_new(char *domain) dom = kore_malloc(sizeof(*dom)); dom->accesslog = -1; - dom->certfile = NULL; + dom->cafile = NULL; dom->certkey = NULL; dom->ssl_ctx = NULL; + dom->certfile = NULL; dom->domain = kore_strdup(domain); TAILQ_INIT(&(dom->handlers)); TAILQ_INSERT_TAIL(&domains, dom, list); @@ -55,6 +58,8 @@ kore_domain_new(char *domain) void kore_domain_sslstart(struct kore_domain *dom) { + STACK_OF(X509_NAME) *certs; + #if !defined(OPENSSL_NO_EC) EC_KEY *ecdh; #endif @@ -93,6 +98,22 @@ kore_domain_sslstart(struct kore_domain *dom) if (ssl_no_compression) SSL_CTX_set_options(dom->ssl_ctx, SSL_OP_NO_COMPRESSION); + if (dom->cafile != NULL) { + if ((certs = SSL_load_client_CA_file(dom->cafile)) == NULL) { + fatal("SSL_load_client_CA_file(%s): %s", + dom->cafile, ssl_errno_s); + } + + SSL_CTX_load_verify_locations(dom->ssl_ctx, dom->cafile, NULL); + SSL_CTX_set_verify_depth(dom->ssl_ctx, 1); + SSL_CTX_set_client_CA_list(dom->ssl_ctx, certs); + SSL_CTX_set_verify(dom->ssl_ctx, SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + } + + SSL_CTX_set_session_id_context(dom->ssl_ctx, + (unsigned char *)SSL_SESSION_ID, strlen(SSL_SESSION_ID)); + SSL_CTX_set_mode(dom->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_mode(dom->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); diff --git a/src/kore.c b/src/kore.c @@ -135,6 +135,14 @@ kore_ssl_sni_cb(SSL *ssl, int *ad, void *arg) if (sname != NULL && (dom = kore_domain_lookup(sname)) != NULL) { kore_debug("kore_ssl_sni_cb(): Using %s CTX", sname); SSL_set_SSL_CTX(ssl, dom->ssl_ctx); + + if (dom->cafile != NULL) { + SSL_set_verify(ssl, SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + } else { + SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); + } + return (SSL_TLSEXT_ERR_OK); }